Finishing timepoint browser behavior

This commit is contained in:
Bruno Alves de Faria 2017-10-16 07:20:37 -02:00
parent d721c0dbde
commit d787ed2cb9
17 changed files with 118 additions and 95 deletions

View File

@ -2,8 +2,8 @@
<div class="viewerSection"> <div class="viewerSection">
<div class="sidebarMenu sidebar-left {{#if leftSidebarOpen}}sidebar-open{{/if}}"> <div class="sidebarMenu sidebar-left {{#if leftSidebarOpen}}sidebar-open{{/if}}">
{{>timepointBrowserList (extend timepointBrowserData scrollableClass='p-a-1')}} {{>timepointBrowserList (extend timepointBrowserData scrollableClass='p-a-1')}}
<!-- <hr> <!-- <hr> -->
{{>studyTimepointBrowser (clone this)}} --> <!-- {{>studyTimepointBrowser (clone this)}} -->
</div> </div>
<div class="mainContent {{#if leftSidebarOpen}}sidebar-left-open{{/if}} {{#if rightSidebarOpen}}sidebar-right-open{{/if}}"> <div class="mainContent {{#if leftSidebarOpen}}sidebar-left-open{{/if}} {{#if rightSidebarOpen}}sidebar-right-open{{/if}}">
{{>viewerMain (clone this)}} {{>viewerMain (clone this)}}

View File

@ -1,3 +1,4 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
Template.viewerSection.events({ Template.viewerSection.events({
@ -7,6 +8,34 @@ Template.viewerSection.events({
} }
window.ResizeViewportManager.handleResize(); window.ResizeViewportManager.handleResize();
},
'ohif.studies.study.click'(event, instance) {
const $element = $(event.currentTarget);
// Defer the active class toggling to wait for child template rendering
Meteor.defer(() => {
// Remove max height restriction from studies browser
const $studiesBrowser = $element.closest('.timepoint-browser-studies');
$studiesBrowser.css('max-height', '');
// Remove active class from sibling studies
$element.siblings().removeClass('active');
// Toggle the active class on clicked study
$element.toggleClass('active');
// Adjust the max height for studiesBrowser when series transition is finished
const $seriesBrowser = $element.find('.study-browser-series');
$seriesBrowser.one('transitionend', () => $studiesBrowser.adjustMax('height'));
});
},
'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'));
} }
}); });
@ -26,15 +55,8 @@ Template.viewerSection.helpers({
return { return {
timepointApi, timepointApi,
timepoints, timepoints,
timepointChildTemplate: 'timepointBrowserStudies', timepointChildTemplate: 'timepointBrowserStudies',
studyChildTemplate: 'studyBrowserSeries', studyChildTemplate: 'studyBrowserSeries'
studyClickCallback(studyInformation, element) {
const $element = $(element);
$element.siblings().removeClass('active');
$element.toggleClass('active');
}
}; };
} }
}); });

View File

@ -27,8 +27,10 @@ $.fn.tempShow = function(callback) {
}; };
// Adjust the max width/height to enable CSS3 transitions // Adjust the max width/height to enable CSS3 transitions
$.fn.adjustMax = function(dimension) { $.fn.adjustMax = function(dimension, modifierFn) {
const $element = $(this); const $element = $(this);
// Temporarily make the element visible to allow getting its dimensions
$element.tempShow(() => { $element.tempShow(() => {
const maxProperty = `max-${dimension}`; const maxProperty = `max-${dimension}`;

View File

@ -1,2 +1,2 @@
body *.visible body *.visible
display: block !important display: block !important

View File

@ -1,16 +1,16 @@
<template name="timepointBrowserItem"> <template name="timepointBrowserItem">
<div class="timepoint-browser-item"> <div class="timepoint-browser-item">
<div class="timepointEntry p-y-2"> <div class="timepoint-item p-y-2">
<div class="timepointDetails clearfix"> <div class="timepoint-details clearfix">
<div class="timepointFollowupTitle pull-left"> <div class="timepoint-title pull-left">
{{this.timepointApi.title timepoint}} {{this.timepointApi.title timepoint}}
</div> </div>
<div class="expandIcon pull-right"> <div class="timepoint-expand-icon pull-right">
<i class="fa fa-chevron-down"></i> <i class="fa fa-chevron-down"></i>
</div> </div>
<div class="timepointDate pull-right m-r-1">{{formatDA this.timepoint.earliestDate 'D-MMM-YYYY'}}</div> <div class="timepoint-date pull-right m-r-1">{{formatDA this.timepoint.earliestDate 'D-MMM-YYYY'}}</div>
</div> </div>
<div class="timepointModalities">{{choose instance.summary.get 'Click to load'}}</div> <div class="timepoint-summary">{{choose instance.summary.get 'Click to load'}}</div>
</div> </div>
{{#if this.timepointChildTemplate}} {{#if this.timepointChildTemplate}}
{{#if and (not instance.loading.get) instance.loaded}} {{#if and (not instance.loading.get) instance.loaded}}

View File

@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var'; import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { $ } from 'meteor/jquery'; import { $ } from 'meteor/jquery';
import { _ } from 'meteor/underscore'; import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
@ -52,16 +53,21 @@ Template.timepointBrowserItem.onCreated(() => {
}); });
Template.timepointBrowserItem.events({ Template.timepointBrowserItem.events({
'click .timepointEntry'(event, instance) { 'click .timepoint-item'(event, instance) {
const element = event.currentTarget.parentElement; const element = event.currentTarget.parentElement;
const $element = $(element); const $element = $(element);
const triggerClick = () => {
$element.trigger('ohif.lesiontracker.timepoint.click', instance.data.timepoint);
};
if (!instance.loaded) { if (!instance.loaded) {
instance.loadStudies().then(() => { instance.loadStudies().then(() => {
$element.addClass('active'); Tracker.afterFlush(triggerClick);
instance.setModalitiesSummary(); instance.setModalitiesSummary();
}); });
} else { } else {
$element.toggleClass('active'); triggerClick();
} }
} }
}); });

View File

@ -2,70 +2,75 @@
.timepoint-browser-item .timepoint-browser-item
.timepointEntry .timepoint-item
cursor: pointer cursor: pointer
font-size: 13px font-size: 13px
.timepoint-browser-studies
opacity: 1
overflow: hidden
transform(translateY(0))
transform-origin(50% 0%)
transition(max-height 0.3s ease\, opacity 0.3s ease\, transform 0.3s ease)
&:not(.active) .timepoint-browser-studies &:not(.active) .timepoint-browser-studies
max-height: 0 !important max-height: 0 !important
opacity: 0
transform(translateY(-100%))
.timepointDate .timepoint-studies-container
opacity: 0
transform(translateY(-100%))
.timepoint-browser-studies
overflow: hidden
transition(max-height 0.3s ease)
.timepoint-studies-container
opacity: 1
transition(opacity 0.3s ease\, transform 0.3s ease)
transform(translateY(0))
transform-origin(50% 0%)
.timepoint-date
opacity: 1 opacity: 1
&.active &.active
.timepointModalities .timepoint-summary
max-height: 0 max-height: 0
opacity: 0 opacity: 0
.timepointDate .timepoint-date
opacity: 0 opacity: 0
.expandIcon i .timepoint-expand-icon i
transform: rotateX(180deg) transform: rotateX(180deg)
.timepointFollowupTitle .timepoint-title
font-size: 14px font-size: 14px
theme('color', '$textSecondaryColor') theme('color', '$textSecondaryColor')
text-transform: uppercase text-transform: uppercase
& &
.expandIcon i, .timepoint-expand-icon i,
.timepointFollowupTitle, .timepoint-title,
.timepointDate, .timepoint-date,
.timepointModalities .timepoint-summary
theme('color', '$textSecondaryColor') theme('color', '$textSecondaryColor')
transition($sidebarTransition) transition($sidebarTransition)
&:hover &:hover
&, &,
.timepointFollowupTitle, .timepoint-title,
.expandIcon i, .timepoint-expand-icon i,
.timepointDate, .timepoint-date,
.timepointModalities .timepoint-summary
theme('color', '$textPrimaryColor') !important theme('color', '$textPrimaryColor') !important
.timepointDetails .timepoint-details
.timepointModalities .timepoint-summary
line-height: 25px line-height: 25px
.timepointModalities .timepoint-summary
height: 25px height: 25px
max-height: 25px max-height: 25px
opacity: 1 opacity: 1
overflow: hidden overflow: hidden
.expandIcon i .timepoint-expand-icon i
theme('color', '$defaultColor') theme('color', '$defaultColor')
.timepointFollowupTitle .timepoint-title
theme('color', '$textPrimaryColor') theme('color', '$textPrimaryColor')
padding-top: 2px padding-top: 2px

View File

@ -2,6 +2,7 @@
<div class="timepoint-browser-list {{this.class}}"> <div class="timepoint-browser-list {{this.class}}">
{{#each timepoint in this.timepoints}} {{#each timepoint in this.timepoints}}
{{>timepointBrowserItem (clone this timepoint=timepoint)}} {{>timepointBrowserItem (clone this timepoint=timepoint)}}
<hr>
{{/each}} {{/each}}
</div> </div>
</template> </template>

View File

@ -1,5 +1,7 @@
<template name="timepointBrowserStudies"> <template name="timepointBrowserStudies">
<div class="timepoint-browser-studies"> <div class="timepoint-browser-studies">
{{>studyBrowserList this}} <div class="timepoint-studies-container">
{{>studyBrowserList this}}
</div>
</div> </div>
</template> </template>

View File

@ -1,16 +1,5 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
Template.timepointBrowserStudies.onRendered(() => { Template.timepointBrowserStudies.onRendered(() => {
const instance = Template.instance(); Template.instance().$('.timepoint-browser-studies').adjustMax('height');
const $container = instance.$('.timepoint-browser-studies');
instance.adjustMaxHeight = () => $container.adjustMax('height');
instance.adjustMaxHeight();
});
Template.timepointBrowserStudies.events({
'ohif.studies.study.click'(event, instance) {
// FIXME disable all transitions during $.tempShow
Meteor.setTimeout(instance.adjustMaxHeight, 300);
}
}); });

View File

@ -15,7 +15,9 @@
</div> </div>
</div> </div>
{{#if this.studyChildTemplate}} {{#if this.studyChildTemplate}}
{{>Template.dynamic template=this.studyChildTemplate data=(clone this)}} {{#if and (not isLoading) instance.loaded}}
{{>Template.dynamic template=this.studyChildTemplate data=(clone this)}}
{{/if}}
{{/if}} {{/if}}
</div> </div>
</template> </template>

View File

@ -1,5 +1,6 @@
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var'; import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { $ } from 'meteor/jquery'; import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
@ -17,27 +18,20 @@ Template.studyBrowserItem.events({
'click .study-item'(event, instance) { 'click .study-item'(event, instance) {
if (instance.loading.get()) return; if (instance.loading.get()) return;
const { studyClickCallback, studyInformation } = instance.data; const { studyInformation } = instance.data;
const element = event.currentTarget.parentElement; const element = event.currentTarget.parentElement;
const $element = $(element); const $element = $(element);
const triggerClick = () => $element.trigger('ohif.studies.study.click', studyInformation);
const triggerClickCallback = () => {
if (typeof studyClickCallback === 'function') {
studyClickCallback(studyInformation, element);
}
$element.trigger('ohif.studies.study.click', studyInformation);
};
if (instance.loaded) { if (instance.loaded) {
triggerClickCallback(); triggerClick();
} else { } else {
instance.loading.set(true); instance.loading.set(true);
OHIF.studies.retrieveStudyMetadata(studyInformation.studyInstanceUid).then(() => { OHIF.studies.retrieveStudyMetadata(studyInformation.studyInstanceUid).then(() => {
instance.loaded = true; instance.loaded = true;
instance.loading.set(false); instance.loading.set(false);
$element.trigger('ohif.studies.study.load', studyInformation); $element.trigger('ohif.studies.study.load', studyInformation);
triggerClickCallback(); Tracker.afterFlush(triggerClick);
}); });
} }
} }

View File

@ -55,13 +55,11 @@ $spacerY = 12px
.study-browser-series .study-browser-series
overflow: hidden overflow: hidden
transform(translateY(0)) transition(max-height 0.3s ease)
transform-origin(50% 0%)
transition($sidebarTransition)
.study-series-container .study-series-container
opacity: 1 opacity: 1
transition($sidebarTransition) transition(opacity 0.3s ease\, transform 0.3s ease)
transform(translateY(0)) transform(translateY(0))
transform-origin(50% 0%) transform-origin(50% 0%)

View File

@ -17,7 +17,7 @@ Template.studyTimepoint.onRendered(() => {
const $studies = instance.$('.studyTimepoint'); const $studies = instance.$('.studyTimepoint');
const $wrapper = $studies.closest('.studyTimepointWrapper'); const $wrapper = $studies.closest('.studyTimepointWrapper');
const $timepoint = $wrapper.closest('.timepointEntry'); const $timepoint = $wrapper.closest('.timepoint-item');
const studiesVisible = $studies.is(':visible'); const studiesVisible = $studies.is(':visible');
if (!studiesVisible) { if (!studiesVisible) {

View File

@ -4,5 +4,5 @@
overflow: hidden overflow: hidden
transition($sidebarTransition) transition($sidebarTransition)
.timepointEntry:not(.active) .studyTimepointWrapper .timepoint-item:not(.active) .studyTimepointWrapper
max-height: 0 !important max-height: 0 !important

View File

@ -8,20 +8,22 @@
<div class="p-x-1"> <div class="p-x-1">
{{#if timepointList.length}} {{#if timepointList.length}}
{{#each timepoint in timepointList}} {{#each timepoint in timepointList}}
<div class="timepointEntry p-y-2"> <div class="timepoint-browser-item">
<div class="timepointHeader"> <div class="timepoint-item p-y-2">
<div class="timepointDetails clearfix"> <div class="timepointHeader">
<div class="timepointFollowupTitle pull-left"> <div class="timepoint-details clearfix">
{{timepointApi.title timepoint}} <div class="timepoint-title pull-left">
{{timepointApi.title timepoint}}
</div>
<div class="timepoint-expand-icon pull-right">
<i class="fa fa-chevron-down"></i>
</div>
<div class="timepoint-date pull-right m-r-1">{{formatDA timepoint.earliestDate 'D-MMM-YYYY'}}</div>
</div> </div>
<div class="expandIcon pull-right"> <div class="timepoint-summary">{{modalitiesSummary timepoint}}</div>
<i class="fa fa-chevron-down"></i>
</div>
<div class="timepointDate pull-right m-r-1">{{formatDA timepoint.earliestDate 'D-MMM-YYYY'}}</div>
</div> </div>
<div class="timepointModalities">{{modalitiesSummary timepoint}}</div> {{>studyTimepoint studies=(studies timepoint) index=@index viewportIndex=this.viewportIndex currentStudy=this.currentStudy}}
</div> </div>
{{>studyTimepoint studies=(studies timepoint) index=@index viewportIndex=this.viewportIndex currentStudy=this.currentStudy}}
</div> </div>
<hr> <hr>
{{/each}} {{/each}}

View File

@ -53,10 +53,10 @@ Template.studyTimepointBrowser.onRendered(() => {
const type = instance.timepointViewType.get(); const type = instance.timepointViewType.get();
// Removes all active classes to collapse the timepoints and studies // Removes all active classes to collapse the timepoints and studies
instance.$('.timepointEntry, .study-browser-item').removeClass('active'); instance.$('.timepoint-item, .study-browser-item').removeClass('active');
if (type === 'key' && !instance.data.currentStudy) { if (type === 'key' && !instance.data.currentStudy) {
// Show only first timepoint expanded for key timepoints // Show only first timepoint expanded for key timepoints
instance.$('.timepointEntry:first').addClass('active'); instance.$('.timepoint-item:first').addClass('active');
} }
}); });
@ -70,7 +70,7 @@ Template.studyTimepointBrowser.onRendered(() => {
instance.$(`.study-browser-item[data-uid='${studyInstanceUid}']`).addClass('active'); instance.$(`.study-browser-item[data-uid='${studyInstanceUid}']`).addClass('active');
}); });
// Show only first timepoint expanded for key timepoints // Show only first timepoint expanded for key timepoints
instance.$('.timepointEntry:first').addClass('active'); instance.$('.timepoint-item:first').addClass('active');
}); });
instance.autorun(() => { instance.autorun(() => {
@ -95,7 +95,7 @@ Template.studyTimepointBrowser.onRendered(() => {
Template.studyTimepointBrowser.events({ Template.studyTimepointBrowser.events({
'click .timepointHeader'(event, instance) { 'click .timepointHeader'(event, instance) {
const $timepoint = $(event.currentTarget).closest('.timepointEntry'); const $timepoint = $(event.currentTarget).closest('.timepoint-item');
// Recalculates the timepoint height to make CSS transition smoother // Recalculates the timepoint height to make CSS transition smoother
$timepoint.find('.studyTimepoint').trigger('displayStateChanged'); $timepoint.find('.studyTimepoint').trigger('displayStateChanged');