Using the new time point browser on the sidebar
This commit is contained in:
parent
fd9cfed8e9
commit
d721c0dbde
@ -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)}}
|
||||||
|
|||||||
@ -25,7 +25,16 @@ Template.viewerSection.helpers({
|
|||||||
const timepoints = timepointApi.all();
|
const timepoints = timepointApi.all();
|
||||||
return {
|
return {
|
||||||
timepointApi,
|
timepointApi,
|
||||||
timepoints
|
timepoints,
|
||||||
|
|
||||||
|
timepointChildTemplate: 'timepointBrowserStudies',
|
||||||
|
studyChildTemplate: 'studyBrowserSeries',
|
||||||
|
|
||||||
|
studyClickCallback(studyInformation, element) {
|
||||||
|
const $element = $(element);
|
||||||
|
$element.siblings().removeClass('active');
|
||||||
|
$element.toggleClass('active');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
import './list.html';
|
|
||||||
import './item.html';
|
import './item.html';
|
||||||
import './item.js';
|
import './item.js';
|
||||||
|
import './item.styl';
|
||||||
|
import './list.html';
|
||||||
|
import './studies.html';
|
||||||
|
import './studies.js';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template name="timepointBrowserItem">
|
<template name="timepointBrowserItem">
|
||||||
|
<div class="timepoint-browser-item">
|
||||||
<div class="timepointEntry p-y-2">
|
<div class="timepointEntry p-y-2">
|
||||||
<div class="timepointHeader">
|
|
||||||
<div class="timepointDetails clearfix">
|
<div class="timepointDetails clearfix">
|
||||||
<div class="timepointFollowupTitle pull-left">
|
<div class="timepointFollowupTitle pull-left">
|
||||||
{{this.timepointApi.title timepoint}}
|
{{this.timepointApi.title timepoint}}
|
||||||
@ -10,7 +10,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="timepointDate pull-right m-r-1">{{formatDA this.timepoint.earliestDate 'D-MMM-YYYY'}}</div>
|
<div class="timepointDate pull-right m-r-1">{{formatDA this.timepoint.earliestDate 'D-MMM-YYYY'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="timepointModalities">{{modalitiesSummary timepoint}}</div> -->
|
<div class="timepointModalities">{{choose instance.summary.get 'Click to load'}}</div>
|
||||||
</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}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,28 +1,67 @@
|
|||||||
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 { $ } from 'meteor/jquery';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
Template.timepointBrowserItem.onCreated(() => {
|
Template.timepointBrowserItem.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
const { timepoint, timepointApi } = instance.data;
|
const { timepoint, timepointApi } = instance.data;
|
||||||
|
|
||||||
|
instance.summary = new ReactiveVar('');
|
||||||
instance.loading = new ReactiveVar(false);
|
instance.loading = new ReactiveVar(false);
|
||||||
instance.loaded = !!(timepoint.studiesData && timepoint.studiesData.length);
|
instance.loaded = !!(timepoint.studiesData && timepoint.studiesData.length);
|
||||||
|
|
||||||
instance.autorun(() => {
|
// Build the modalities summary of all timepoint's studies
|
||||||
if (instance.loaded || !instance.loading.get()) return;
|
instance.setModalitiesSummary = () => {
|
||||||
|
const modalities = {};
|
||||||
|
timepoint.studiesData.forEach(study => {
|
||||||
|
const modality = study.modalities || 'UN';
|
||||||
|
modalities[modality] = modalities[modality] + 1 || 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
const summary = [];
|
||||||
|
_.each(modalities, (count, modality) => summary.push(`${count} ${modality}`));
|
||||||
|
|
||||||
|
instance.summary.set(summary.join(', '));
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.loadStudies = () => new Promise((resolve, reject) => {
|
||||||
const filter = { studyInstanceUid: timepoint.studyInstanceUids };
|
const filter = { studyInstanceUid: timepoint.studyInstanceUids };
|
||||||
|
instance.summary.set('Loading...');
|
||||||
Meteor.call('StudyListSearch', filter, (error, studiesData) => {
|
Meteor.call('StudyListSearch', filter, (error, studiesData) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
const text = 'An error has occurred while retrieving studies information';
|
const text = 'An error has occurred while retrieving studies information';
|
||||||
OHIF.ui.notifications.danger({ text });
|
OHIF.ui.notifications.danger({ text });
|
||||||
OHIF.log.error(error);
|
OHIF.log.error(error);
|
||||||
|
reject(error);
|
||||||
} else {
|
} else {
|
||||||
timepoint.studiesData = studiesData;
|
timepoint.studiesData = studiesData;
|
||||||
timepointApi.timepoints.update(timepoint._id, { $set: studiesData });
|
timepointApi.timepoints.update(timepoint._id, { $set: { studiesData } });
|
||||||
|
instance.loaded = true;
|
||||||
|
instance.loading.set(false);
|
||||||
|
resolve(studiesData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (instance.loaded) {
|
||||||
|
instance.setModalitiesSummary();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.timepointBrowserItem.events({
|
||||||
|
'click .timepointEntry'(event, instance) {
|
||||||
|
const element = event.currentTarget.parentElement;
|
||||||
|
const $element = $(element);
|
||||||
|
if (!instance.loaded) {
|
||||||
|
instance.loadStudies().then(() => {
|
||||||
|
$element.addClass('active');
|
||||||
|
instance.setModalitiesSummary();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$element.toggleClass('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,71 @@
|
|||||||
|
@require '{ohif:design}/app'
|
||||||
|
|
||||||
|
.timepoint-browser-item
|
||||||
|
|
||||||
|
.timepointEntry
|
||||||
|
cursor: pointer
|
||||||
|
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
|
||||||
|
max-height: 0 !important
|
||||||
|
opacity: 0
|
||||||
|
transform(translateY(-100%))
|
||||||
|
|
||||||
|
.timepointDate
|
||||||
|
opacity: 1
|
||||||
|
|
||||||
|
&.active
|
||||||
|
.timepointModalities
|
||||||
|
max-height: 0
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
.timepointDate
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
.expandIcon i
|
||||||
|
transform: rotateX(180deg)
|
||||||
|
|
||||||
|
.timepointFollowupTitle
|
||||||
|
font-size: 14px
|
||||||
|
theme('color', '$textSecondaryColor')
|
||||||
|
text-transform: uppercase
|
||||||
|
|
||||||
|
&
|
||||||
|
.expandIcon i,
|
||||||
|
.timepointFollowupTitle,
|
||||||
|
.timepointDate,
|
||||||
|
.timepointModalities
|
||||||
|
theme('color', '$textSecondaryColor')
|
||||||
|
transition($sidebarTransition)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
&,
|
||||||
|
.timepointFollowupTitle,
|
||||||
|
.expandIcon i,
|
||||||
|
.timepointDate,
|
||||||
|
.timepointModalities
|
||||||
|
theme('color', '$textPrimaryColor') !important
|
||||||
|
|
||||||
|
.timepointDetails
|
||||||
|
.timepointModalities
|
||||||
|
line-height: 25px
|
||||||
|
|
||||||
|
.timepointModalities
|
||||||
|
height: 25px
|
||||||
|
max-height: 25px
|
||||||
|
opacity: 1
|
||||||
|
overflow: hidden
|
||||||
|
|
||||||
|
.expandIcon i
|
||||||
|
theme('color', '$defaultColor')
|
||||||
|
|
||||||
|
.timepointFollowupTitle
|
||||||
|
theme('color', '$textPrimaryColor')
|
||||||
|
padding-top: 2px
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template name="timepointBrowserList">
|
<template name="timepointBrowserList">
|
||||||
{{#scrollArea class=(concat 'full-height ' this.class) scrollableClass=this.scrollableClass}}
|
<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)}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/scrollArea}}
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
<template name="timepointBrowserStudies">
|
||||||
|
<div class="timepoint-browser-studies">
|
||||||
|
{{>studyBrowserList this}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
|
||||||
|
Template.timepointBrowserStudies.onRendered(() => {
|
||||||
|
const instance = Template.instance();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -40,6 +40,7 @@ export const schema = new SimpleSchema({
|
|||||||
studiesData: {
|
studiesData: {
|
||||||
type: [Object],
|
type: [Object],
|
||||||
label: 'Studies data to allow lazy loading',
|
label: 'Studies data to allow lazy loading',
|
||||||
optional: true
|
optional: true,
|
||||||
|
blackbox: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -20,12 +20,13 @@ Template.studyBrowserItem.events({
|
|||||||
const { studyClickCallback, studyInformation } = instance.data;
|
const { studyClickCallback, studyInformation } = instance.data;
|
||||||
const element = event.currentTarget.parentElement;
|
const element = event.currentTarget.parentElement;
|
||||||
const $element = $(element);
|
const $element = $(element);
|
||||||
$element.trigger('ohif.studies.study.click', studyInformation);
|
|
||||||
|
|
||||||
const triggerClickCallback = () => {
|
const triggerClickCallback = () => {
|
||||||
if (typeof studyClickCallback === 'function') {
|
if (typeof studyClickCallback === 'function') {
|
||||||
studyClickCallback(studyInformation, element);
|
studyClickCallback(studyInformation, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$element.trigger('ohif.studies.study.click', studyInformation);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (instance.loaded) {
|
if (instance.loaded) {
|
||||||
|
|||||||
@ -195,22 +195,12 @@ Template.studyTimepointBrowser.helpers({
|
|||||||
|
|
||||||
const studies = instance.getStudies(timepoint);
|
const studies = instance.getStudies(timepoint);
|
||||||
|
|
||||||
const includedUids = new Set();
|
|
||||||
const modalities = {};
|
const modalities = {};
|
||||||
studies.forEach(study => {
|
studies.forEach(study => {
|
||||||
const modality = study.modalities || 'UN';
|
const modality = study.modalities || 'UN';
|
||||||
modalities[modality] = modalities[modality] + 1 || 1;
|
modalities[modality] = modalities[modality] + 1 || 1;
|
||||||
includedUids.add(study.studyInstanceUid);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (_.isArray(timepoint.studiesData)) {
|
|
||||||
timepoint.studiesData.forEach(({ modality, studyInstanceUid }) => {
|
|
||||||
if (includedUids.has(studyInstanceUid)) return;
|
|
||||||
modalities[modality] = modalities[modality] + 1 || 1;
|
|
||||||
includedUids.add(studyInstanceUid);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
_.each(modalities, (count, modality) => {
|
_.each(modalities, (count, modality) => {
|
||||||
result.push(`${count} ${modality}`);
|
result.push(`${count} ${modality}`);
|
||||||
|
|||||||
@ -28,54 +28,6 @@ $timepointButtonHeight = 55px
|
|||||||
.studyTimepointScrollArea
|
.studyTimepointScrollArea
|
||||||
padding-top: $timepointButtonHeight
|
padding-top: $timepointButtonHeight
|
||||||
|
|
||||||
.timepointEntry
|
|
||||||
&.active
|
|
||||||
.timepointModalities
|
|
||||||
height: 0
|
|
||||||
.timepointDate
|
|
||||||
display: none
|
|
||||||
.expandIcon i
|
|
||||||
transform: rotateX(180deg)
|
|
||||||
.timepointFollowupTitle
|
|
||||||
font-size: 14px
|
|
||||||
theme('color', '$textSecondaryColor')
|
|
||||||
text-transform: uppercase
|
|
||||||
|
|
||||||
.timepointHeader
|
|
||||||
cursor: pointer
|
|
||||||
font-size: 13px
|
|
||||||
|
|
||||||
&
|
|
||||||
.expandIcon i
|
|
||||||
.timepointFollowupTitle
|
|
||||||
.timepointDate
|
|
||||||
.timepointModalities
|
|
||||||
theme('color', '$textSecondaryColor')
|
|
||||||
transition($sidebarTransition)
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
&
|
|
||||||
.timepointFollowupTitle
|
|
||||||
.expandIcon i
|
|
||||||
.timepointDate
|
|
||||||
.timepointModalities
|
|
||||||
theme('color', '$textPrimaryColor') !important
|
|
||||||
|
|
||||||
.timepointDetails
|
|
||||||
.timepointModalities
|
|
||||||
line-height: 25px
|
|
||||||
|
|
||||||
.timepointModalities
|
|
||||||
height: 25px
|
|
||||||
overflow: hidden
|
|
||||||
|
|
||||||
.expandIcon i
|
|
||||||
theme('color', '$defaultColor')
|
|
||||||
|
|
||||||
.timepointFollowupTitle
|
|
||||||
theme('color', '$textPrimaryColor')
|
|
||||||
padding-top: 2px
|
|
||||||
|
|
||||||
.studyTimepointScrollArea
|
.studyTimepointScrollArea
|
||||||
height: 100%
|
height: 100%
|
||||||
overflow-x: hidden
|
overflow-x: hidden
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user