Final adjustments on quickSwitch

This commit is contained in:
Bruno Alves de Faria 2017-10-20 15:18:54 -02:00
parent 89f6bd4610
commit 37137b9331
13 changed files with 170 additions and 80 deletions

View File

@ -7,13 +7,6 @@
{{>toolbarSectionTools toolbarButtons=toolbarButtons}}
{{#if splitView}}
{{>studySeriesQuickSwitch (clone this side="right" viewportIndex=1)}}
{{>studySeriesQuickSwitch (clone this side="left" viewportIndex=0)}}
{{else}}
{{>studySeriesQuickSwitch (clone this side="middle" viewportIndex=0)}}
{{/if}}
<div id="toolbarSectionEntry" class="toolbarSectionEntry pull-right rm-l-1 p-x-1">
{{>caseProgress}}
</div>

View File

@ -4,19 +4,6 @@ import { OHIF } from 'meteor/ohif:core';
import { Viewerbase } from 'meteor/ohif:viewerbase';
Template.toolbarSection.helpers({
// Returns true if the view shall be split in two viewports
splitView() {
// Run this computation every time the viewports are updated
Session.get('LayoutManagerUpdated');
// Stops here if layout manager is not defined yet
if (!Viewerbase.layoutManager) {
return;
}
return Viewerbase.layoutManager.viewportData.length > 1;
},
leftSidebarToggleButtonData() {
const instance = Template.instance();
return {

View File

@ -1,5 +1,6 @@
import { Template } from 'meteor/templating';
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core';
Template.scrollArea.onCreated(() => {
const instance = Template.instance();
@ -16,17 +17,20 @@ Template.scrollArea.onCreated(() => {
Template.scrollArea.onRendered(() => {
const instance = Template.instance();
const { config } = instance;
if (config.hideScrollbar) {
const $scrollable = instance.$('.scrollable').first();
const scrollable = $scrollable[0];
const x = config.scrollX ? 1 : 0;
const y = config.scrollY ? 1 : 0;
$scrollable.css({
'margin-right': 0 - (scrollable.offsetWidth - scrollable.clientWidth) * y,
'margin-bottom': 0 - (scrollable.offsetHeight - scrollable.clientHeight) * x
});
}
instance.adjustMargins = _.throttle(() => {
const { config } = instance;
if (config.hideScrollbar) {
const $scrollable = instance.$('.scrollable').first();
const x = config.scrollX ? 1 : 0;
const y = config.scrollY ? 1 : 0;
const scrollbarSize = OHIF.ui.getScrollbarSize();
$scrollable.css({
'margin-right': 0 - (scrollbarSize[0]) * y,
'margin-bottom': 0 - (scrollbarSize[1]) * x
});
}
}, 150);
instance.$scrollable = instance.$('.scrollable').first();
instance.scrollHandler = _.throttle(event => {
@ -50,9 +54,17 @@ Template.scrollArea.onRendered(() => {
if (scrollTop + height < scrollHeight) {
$scrollArea.addClass('can-scroll-down');
}
}, 300);
}, 150);
instance.scrollHandler();
instance.adjustMargins();
$(window).on('resize', instance.adjustMargins);
});
Template.scrollArea.onDestroyed(() => {
const instance = Template.instance();
$(window).off('resize', instance.adjustMargins);
});
Template.scrollArea.events({

View File

@ -9,6 +9,7 @@ $scrollNavSize = 24px
.scrollable
max-height: inherit
overflow: hidden
zoom: 1
&.scroll-x
overflow-x: scroll

View File

@ -26,3 +26,45 @@ OHIF.ui.getOffset = element => {
top
};
};
/**
* Get the vertical and horizontal scrollbar sizes
* Got from https://stackoverflow.com/questions/986937/how-can-i-get-the-browsers-scrollbar-sizes
*
* @returns {Array} Array containing the scrollbar horizontal and vertical sizes
*/
OHIF.ui.getScrollbarSize = () => {
const inner = document.createElement('p');
inner.style.width = '100%';
inner.style.height = '100%';
const outer = document.createElement('div');
outer.style.position = 'absolute';
outer.style.top = '0px';
outer.style.left = '0px';
outer.style.visibility = 'hidden';
outer.style.width = '100px';
outer.style.height = '100px';
outer.style.overflow = 'hidden';
outer.appendChild(inner);
document.body.appendChild(outer);
const w1 = inner.offsetWidth;
const h1 = inner.offsetHeight;
outer.style.overflow = 'scroll';
let w2 = inner.offsetWidth;
let h2 = inner.offsetHeight;
if (w1 === w2) {
w2 = outer.clientWidth;
}
if (h1 === h2) {
h2 = outer.clientHeight;
}
document.body.removeChild(outer);
return [(w1 - w2), (h1 - h2)];
};

View File

@ -13,8 +13,8 @@
<div class="timepoint-summary">{{choose instance.summary.get 'Click to load'}}</div>
</div>
{{#if this.timepointChildTemplate}}
{{#if and (not instance.loading.get) instance.loaded}}
{{>Template.dynamic template=this.timepointChildTemplate data=(clone this studiesInformation=timepoint.studiesData)}}
{{#if instance.studiesData.get}}
{{>Template.dynamic template=this.timepointChildTemplate data=(clone this studiesInformation=instance.studiesData.get)}}
{{/if}}
{{/if}}
</div>

View File

@ -8,15 +8,28 @@ import { OHIF } from 'meteor/ohif:core';
Template.timepointBrowserItem.onCreated(() => {
const instance = Template.instance();
const { timepoint, timepointApi } = instance.data;
const { timepointId } = timepoint;
const hasStudiesData = !!(timepoint.studiesData && timepoint.studiesData.length);
instance.summary = new ReactiveVar('');
instance.loading = new ReactiveVar(false);
instance.loaded = !!(timepoint.studiesData && timepoint.studiesData.length);
instance.studiesData = new ReactiveVar(hasStudiesData ? timepoint.studiesData : null);
const updateStudiesData = newDocument => {
const newTimepoint = newDocument || timepointApi.timepoints.findOne({ timepointId });
if (newTimepoint && newTimepoint.studiesData && newTimepoint.studiesData.length) {
instance.studiesData.set(newTimepoint.studiesData);
}
};
timepointApi.timepoints.find({ timepointId }).observe({ changed: updateStudiesData });
// Build the modalities summary of all timepoint's studies
instance.setModalitiesSummary = () => {
const studiesData = instance.studiesData.get();
if (!studiesData) return;
const modalities = {};
timepoint.studiesData.forEach(study => {
studiesData.forEach(study => {
const modality = study.modalities || 'UN';
modalities[modality] = modalities[modality] + 1 || 1;
});
@ -29,20 +42,22 @@ Template.timepointBrowserItem.onCreated(() => {
const filter = { studyInstanceUid: timepoint.studyInstanceUids };
instance.loadStudies = () => OHIF.studies.searchStudies(filter).then(studiesData => {
timepoint.studiesData = studiesData;
instance.studiesData.set(studiesData);
timepointApi.timepoints.update(timepoint._id, { $set: { studiesData } });
instance.loaded = true;
instance.setModalitiesSummary();
instance.loading.set(false);
}).catch(error => {
const text = 'An error has occurred while retrieving studies information';
OHIF.ui.notifications.danger({ text });
OHIF.log.error(error);
});
if (instance.loaded) {
instance.setModalitiesSummary();
}
updateStudiesData();
instance.autorun(() => {
const studiesData = instance.studiesData.get();
if (studiesData) {
instance.setModalitiesSummary();
}
});
});
Template.timepointBrowserItem.events({
@ -58,7 +73,7 @@ Template.timepointBrowserItem.events({
$element.trigger('ohif.lesiontracker.timepoint.click', instance.data.timepoint);
};
if (!instance.loaded) {
if (!instance.studiesData.get()) {
instance.summary.set('Loading...');
instance.loadStudies().then(() => Tracker.afterFlush(triggerClick));
} else {

View File

@ -77,3 +77,9 @@
.timepoint-title
theme('color', '$textPrimaryColor')
padding-top: 2px
.series-quick-switch .timepoint-browser-list
padding: 0 10px
div.timepoint-title
text-transform: none

View File

@ -1,6 +1,6 @@
<template name="timepointBrowserQuickSwitch">
{{>timepointBrowserList (extend timepointBrowserData)}}
{{#unless instance.showAdditional.get}}
<div class='show-additional'>Show additional timepoints</div>
{{/unless}}
{{#if instance.hasAdditional.get}}
<div class='study-item-box additional'>Show additional timepoints</div>
{{/if}}
</template>

View File

@ -2,45 +2,66 @@ import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core';
Template.timepointBrowserQuickSwitch.onCreated(() => {
const instance = Template.instance();
instance.showAdditional = new ReactiveVar(false);
instance.currentTimepoint = new ReactiveVar();
const { timepointApi } = OHIF.viewer;
instance.updateCurrentTimepoint = studyInstanceUid => {
const currentTimepoint = OHIF.viewer.timepointApi.study(studyInstanceUid)[0];
instance.currentTimepoint.set(currentTimepoint);
instance.hasAdditional = new ReactiveVar(false);
instance.showAdditional = new ReactiveVar(false);
instance.selectedTimepoint = new ReactiveVar();
instance.timepoints = new ReactiveVar([]);
instance.updateSelectedTimepoint = studyInstanceUid => {
const selectedTimepoint = timepointApi.study(studyInstanceUid)[0];
instance.selectedTimepoint.set(selectedTimepoint);
};
const currentTimepoint = timepointApi.current();
const filter = { latestDate: { $lte: currentTimepoint.latestDate } };
instance.keyTimepoints = timepointApi.key(filter);
const { viewportIndex } = instance.data;
instance.autorun(() => {
OHIF.viewerbase.layoutManager.observer.depend();
const viewportData = OHIF.viewerbase.layoutManager.viewportData[viewportIndex];
instance.updateCurrentTimepoint(viewportData.studyInstanceUid);
instance.updateSelectedTimepoint(viewportData.studyInstanceUid);
});
instance.autorun(() => {
instance.data.currentStudy.dep.depend();
instance.showAdditional.set(false);
});
instance.autorun(() => {
const showAdditional = instance.showAdditional.get();
instance.hasAdditional.set(!showAdditional && instance.keyTimepoints.length > 1);
});
instance.autorun(() => {
const selectedTimepoint = instance.selectedTimepoint.get();
const showAdditional = instance.showAdditional.get();
const timepoints = showAdditional ? instance.keyTimepoints : [selectedTimepoint];
instance.timepoints.set(timepoints);
});
});
Template.timepointBrowserQuickSwitch.onRendered(() => {
const instance = Template.instance();
instance.autorun(() => {
const currentTimepoint = instance.currentTimepoint.get();
const currentTimepointId = (currentTimepoint && currentTimepoint.timepointId) || '';
const selectedTimepoint = instance.selectedTimepoint.get();
const selectedTimepointId = (selectedTimepoint && selectedTimepoint.timepointId) || '';
const $allBrowserItems = instance.$('.timepoint-browser-item');
const $browserItem = $allBrowserItems.filter(`[data-id=${currentTimepointId}]`);
const $browserItem = $allBrowserItems.filter(`[data-id=${selectedTimepointId}]`);
if (!$browserItem.hasClass('active')) {
$browserItem.find('.timepoint-item').trigger('click');
}
});
instance.autorun(() => {
instance.updateActiveStudy = () => {
const currentStudy = instance.data.currentStudy.get();
const studyInstanceUid = (currentStudy && currentStudy.studyInstanceUid) || '';
Tracker.afterFlush(() => {
@ -48,15 +69,16 @@ Template.timepointBrowserQuickSwitch.onRendered(() => {
$studyBrowserItems.removeClass('active');
$studyBrowserItems.filter(`[data-uid="${studyInstanceUid}"]`).addClass('active');
});
});
};
instance.autorun(instance.updateActiveStudy);
});
Template.timepointBrowserQuickSwitch.events({
'ohif.lesiontracker.timepoint.click'(event, instance) {
const $element = $(event.currentTarget);
// Defer the active class toggling to wait for child template rendering
Meteor.defer(() => $element.toggleClass('active'));
$element.toggleClass('active');
instance.updateActiveStudy();
},
'ohif.studies.study.click'(event, instance, studyInformation) {
@ -65,29 +87,39 @@ Template.timepointBrowserQuickSwitch.events({
instance.data.currentStudy.set(study);
const $studySwitch = $(event.currentTarget).closest('.study-switch');
$studySwitch.siblings('.series-switch').trigger('rescale');
instance.updateCurrentTimepoint(studyInformation.studyInstanceUid);
instance.updateSelectedTimepoint(studyInformation.studyInstanceUid);
// Create a hover bridge to prevent quick switch from closing due to scroll height
Meteor.defer(() => {
const $scrollable = $studySwitch.find('.study-browser>.scrollable');
const offsetY = $scrollable.offset().top + $scrollable.outerHeight();
if (event.clientY > offsetY) {
const hoverHandler = _.throttle(event => {
if (event.clientY <= offsetY) {
$scrollable.css('padding-bottom', '');
$scrollable.off('mousemove', hoverHandler);
$scrollable.off('mouseleave', hoverHandler);
}
}, 100);
$scrollable.css('padding-bottom', event.clientY - offsetY + 20);
$scrollable.on('mousemove', hoverHandler);
$scrollable.one('mouseleave', () => $scrollable.off('mousemove', hoverHandler));
}
});
},
'click .show-additional'(event, instance) {
'click .study-item-box.additional'(event, instance) {
instance.showAdditional.set(true);
},
}
});
Template.timepointBrowserQuickSwitch.helpers({
timepointBrowserData() {
const instance = Template.instance();
const { timepointApi } = OHIF.viewer;
const currentTimepoint = instance.currentTimepoint.get();
let timepoints;
if (instance.showAdditional.get()) {
timepoints = timepointApi.key();
} else {
timepoints = [currentTimepoint];
}
return {
timepointApi,
timepoints,
timepoints: instance.timepoints.get(),
timepointChildTemplate: 'timepointBrowserStudies'
};
}

View File

@ -192,11 +192,11 @@ class TimepointApi {
}
// Return only the key timepoints (current, prior, nadir and baseline)
key() {
key(filter={}) {
const result = [];
// Get all the timepoints
const all = this.all();
const all = this.all(filter);
// Iterate over each timepoint and insert the key ones in the result
_.each(all, (timepoint, index) => {

View File

@ -22,7 +22,13 @@ Template.studyBrowserItem.events({
const { studyInformation } = instance.data;
const element = event.currentTarget.parentElement;
const $element = $(element);
const triggerClick = () => $element.trigger('ohif.studies.study.click', studyInformation);
const triggerClick = () => {
const cloneEvent = _.clone(event);
delete cloneEvent.type;
cloneEvent.currentTarget = cloneEvent.target = element;
const newEvent = $.Event('ohif.studies.study.click', cloneEvent);
$element.trigger(newEvent, studyInformation);
};
if (instance.loaded) {
triggerClick();

View File

@ -3,10 +3,6 @@ import { ReactiveVar } from 'meteor/reactive-var';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
// FIXME >>>> REMOVE
$(document.body).on('keydown', e => (e.keyCode === 69 && $('.quickSwitchWrapper').toggle()) || 1);
OHIF.cornerstone.renderer = '';
Template.seriesQuickSwitch.onCreated(() => {
const instance = Template.instance();