Fixed OHIF Viewer layout / CINE / Hanging Protocol buttons (OHIF-49)
This commit is contained in:
parent
59c851fa57
commit
8b364ce9d0
@ -8,6 +8,9 @@
|
|||||||
<div class="pull-right m-t-1 rm-x-1">
|
<div class="pull-right m-t-1 rm-x-1">
|
||||||
{{>roundedButtonGroup rightSidebarToggleButtonData}}
|
{{>roundedButtonGroup rightSidebarToggleButtonData}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pull-right">
|
||||||
|
{{> toolbarSectionTools toolbarButtons=hangingProtocolButtons}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -82,6 +82,27 @@ Template.toolbarSection.helpers({
|
|||||||
iconClasses: 'fa fa-undo'
|
iconClasses: 'fa fa-undo'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
buttonData.push({
|
||||||
|
id: 'toggleCinePlay',
|
||||||
|
title: 'Toggle CINE Play',
|
||||||
|
classes: 'imageViewerCommand',
|
||||||
|
buttonTemplateName: 'playClipButton'
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonData.push({
|
||||||
|
id: 'toggleCineDialog',
|
||||||
|
title: 'CINE',
|
||||||
|
classes: 'imageViewerCommand',
|
||||||
|
iconClasses: 'fa fa-youtube-play'
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonData.push({
|
||||||
|
id: 'layout',
|
||||||
|
title: 'Layout',
|
||||||
|
iconClasses: 'fa fa-th-large',
|
||||||
|
buttonTemplateName: 'layoutButton'
|
||||||
|
});
|
||||||
|
|
||||||
return buttonData;
|
return buttonData;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -144,6 +165,26 @@ Template.toolbarSection.helpers({
|
|||||||
iconClasses: 'fa fa-trash'
|
iconClasses: 'fa fa-trash'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return buttonData;
|
||||||
|
},
|
||||||
|
|
||||||
|
hangingProtocolButtons() {
|
||||||
|
let buttonData = [];
|
||||||
|
|
||||||
|
buttonData.push({
|
||||||
|
id: 'previousPresentationGroup',
|
||||||
|
title: 'Prev. Stage',
|
||||||
|
iconClasses: 'fa fa-step-backward',
|
||||||
|
buttonTemplateName: 'previousPresentationGroupButton'
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonData.push({
|
||||||
|
id: 'nextPresentationGroup',
|
||||||
|
title: 'Next Stage',
|
||||||
|
iconClasses: 'fa fa-step-forward',
|
||||||
|
buttonTemplateName: 'nextPresentationGroupButton'
|
||||||
|
});
|
||||||
|
|
||||||
return buttonData;
|
return buttonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +193,8 @@ Template.toolbarSection.helpers({
|
|||||||
Template.toolbarSection.onRendered(function() {
|
Template.toolbarSection.onRendered(function() {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|
||||||
|
instance.$('#layout').dropdown();
|
||||||
|
|
||||||
// Set disabled/enabled tool buttons that are set in toolManager
|
// Set disabled/enabled tool buttons that are set in toolManager
|
||||||
const states = toolManager.getToolDefaultStates();
|
const states = toolManager.getToolDefaultStates();
|
||||||
const disabledToolButtons = states.disabledToolButtons;
|
const disabledToolButtons = states.disabledToolButtons;
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
{{#if Template.subscriptionsReady}}
|
{{#if Template.subscriptionsReady}}
|
||||||
<div class="viewerDialogs">
|
<div class="viewerDialogs">
|
||||||
{{> cineDialog}}
|
{{> cineDialog}}
|
||||||
|
{{> layoutChooser }}
|
||||||
</div>
|
</div>
|
||||||
<div id="viewer">
|
<div id="viewer">
|
||||||
{{> toolbarSection (clone this)}}
|
{{> toolbarSection (clone this)}}
|
||||||
|
|||||||
@ -1,24 +1,6 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
OHIF.viewer = OHIF.viewer || {};
|
OHIF.viewer = OHIF.viewer || {};
|
||||||
|
|
||||||
Session.setDefault('activeViewport', false);
|
|
||||||
Session.setDefault('leftSidebar', false);
|
|
||||||
Session.setDefault('rightSidebar', false);
|
|
||||||
|
|
||||||
Template.viewer.onCreated(() => {
|
|
||||||
const instance = Template.instance();
|
|
||||||
|
|
||||||
// Attach the Window resize listener
|
|
||||||
$(window).on('resize', handleResize);
|
|
||||||
|
|
||||||
instance.data.state = new ReactiveDict();
|
|
||||||
instance.data.state.set('leftSidebar', Session.get('leftSidebar'));
|
|
||||||
instance.data.state.set('rightSidebar', Session.get('rightSidebar'));
|
|
||||||
|
|
||||||
Meteor.subscribe('hangingprotocols');
|
|
||||||
|
|
||||||
log.info('viewer onCreated');
|
|
||||||
|
|
||||||
OHIF.viewer.loadIndicatorDelay = 500;
|
OHIF.viewer.loadIndicatorDelay = 500;
|
||||||
OHIF.viewer.defaultTool = 'wwwc';
|
OHIF.viewer.defaultTool = 'wwwc';
|
||||||
OHIF.viewer.refLinesEnabled = true;
|
OHIF.viewer.refLinesEnabled = true;
|
||||||
@ -29,32 +11,28 @@ Template.viewer.onCreated(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
OHIF.viewer.functionList = {
|
OHIF.viewer.functionList = {
|
||||||
invert: element => {
|
toggleCineDialog: toggleCineDialog,
|
||||||
const viewport = cornerstone.getViewport(element);
|
toggleCinePlay: toggleCinePlay,
|
||||||
viewport.invert = !viewport.invert;
|
clearTools: clearTools,
|
||||||
cornerstone.setViewport(element, viewport);
|
resetViewport: resetViewport,
|
||||||
},
|
invert: invert
|
||||||
resetViewport: element => {
|
|
||||||
const enabledElement = cornerstone.getEnabledElement(element);
|
|
||||||
if (enabledElement.fitToWindow === false) {
|
|
||||||
const imageId = enabledElement.image.imageId;
|
|
||||||
const instance = cornerstoneTools.metaData.get('instance', imageId);
|
|
||||||
|
|
||||||
enabledElement.viewport = cornerstone.getDefaultViewport(enabledElement.canvas, enabledElement.image);
|
|
||||||
|
|
||||||
const instanceClassDefaultViewport = getInstanceClassDefaultViewport(instance, enabledElement, imageId);
|
|
||||||
cornerstone.setViewport(element, instanceClassDefaultViewport);
|
|
||||||
} else {
|
|
||||||
cornerstone.reset(element);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clearTools: element => {
|
|
||||||
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
|
|
||||||
toolStateManager.clear(element);
|
|
||||||
cornerstone.updateImage(element);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Session.setDefault('activeViewport', false);
|
||||||
|
Session.setDefault('leftSidebar', false);
|
||||||
|
Session.setDefault('rightSidebar', false);
|
||||||
|
|
||||||
|
Template.viewer.onCreated(() => {
|
||||||
|
const instance = Template.instance();
|
||||||
|
|
||||||
|
instance.data.state = new ReactiveDict();
|
||||||
|
instance.data.state.set('leftSidebar', Session.get('leftSidebar'));
|
||||||
|
instance.data.state.set('rightSidebar', Session.get('rightSidebar'));
|
||||||
|
|
||||||
|
Meteor.subscribe('hangingprotocols');
|
||||||
|
|
||||||
|
log.info('viewer onCreated');
|
||||||
|
|
||||||
if (isTouchDevice()) {
|
if (isTouchDevice()) {
|
||||||
OHIF.viewer.tooltipConfig = {
|
OHIF.viewer.tooltipConfig = {
|
||||||
trigger: 'manual'
|
trigger: 'manual'
|
||||||
@ -96,27 +74,6 @@ Template.viewer.onCreated(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.viewer.onRendered(() => {
|
|
||||||
const instance = Template.instance();
|
|
||||||
|
|
||||||
// Enable hotkeys
|
|
||||||
enableHotkeys();
|
|
||||||
|
|
||||||
const parentNode = document.getElementById('layoutManagerTarget');
|
|
||||||
const studies = instance.data.studies;
|
|
||||||
layoutManager = new LayoutManager(parentNode, studies);
|
|
||||||
|
|
||||||
ProtocolEngine = new HP.ProtocolEngine(layoutManager, studies);
|
|
||||||
HP.setEngine(ProtocolEngine);
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.viewer.onDestroyed(() => {
|
|
||||||
log.info('onDestroyed');
|
|
||||||
|
|
||||||
// Remove the Window resize listener
|
|
||||||
$(window).off('resize', handleResize);
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.viewer.events({
|
Template.viewer.events({
|
||||||
'click .js-toggle-studies'() {
|
'click .js-toggle-studies'() {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
<template name="hangingProtocolButtons">
|
|
||||||
<button id="previousPresentationGroup" type="button"
|
|
||||||
class="btn btn-sm"
|
|
||||||
data-container="body"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="bottom"
|
|
||||||
title="Previous presentation group"
|
|
||||||
disabled="{{ #unless isPreviousAvailable }} true {{ /unless }}">
|
|
||||||
<span class="fa fa-step-backward"></span>
|
|
||||||
</button>
|
|
||||||
<button id="nextPresentationGroup" type="button"
|
|
||||||
class="btn btn-sm"
|
|
||||||
data-container="body"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="bottom"
|
|
||||||
title="Next presentation group"
|
|
||||||
disabled="{{ #unless isNextAvailable }} true {{ /unless }}">
|
|
||||||
<span class="fa fa-step-forward"></span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
Template.hangingProtocolButtons.helpers({
|
|
||||||
/**
|
|
||||||
* Check if a later stage exists for the user to switch to
|
|
||||||
*
|
|
||||||
* @returns {boolean} Whether or not a later stage exists
|
|
||||||
*/
|
|
||||||
isNextAvailable: function() {
|
|
||||||
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
|
||||||
Session.get('LayoutManagerUpdated');
|
|
||||||
|
|
||||||
// If no ProtocolEngine has been defined yet, stop here
|
|
||||||
if (!ProtocolEngine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return whether or not the current stage is the last stage
|
|
||||||
return ProtocolEngine.stage < ProtocolEngine.getNumProtocolStages() - 1;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Check if an earlier stage exists for the user to switch to
|
|
||||||
*
|
|
||||||
* @returns {boolean} Whether or not an earlier stage exists
|
|
||||||
*/
|
|
||||||
isPreviousAvailable: function() {
|
|
||||||
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
|
||||||
Session.get('LayoutManagerUpdated');
|
|
||||||
|
|
||||||
// If no ProtocolEngine has been defined yet, stop here
|
|
||||||
if (!ProtocolEngine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return whether or not the current stage is the first stage
|
|
||||||
return ProtocolEngine.stage > 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.hangingProtocolButtons.events({
|
|
||||||
/**
|
|
||||||
* Switch to the previous Presentation group
|
|
||||||
*
|
|
||||||
* @param event The click event on the button
|
|
||||||
*/
|
|
||||||
'click #previousPresentationGroup': function(event) {
|
|
||||||
// If no ProtocolEngine has been defined yet, do nothing
|
|
||||||
if (!ProtocolEngine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide the button's Bootstrap tooltip in case it was shown
|
|
||||||
$(event.currentTarget).tooltip('hide');
|
|
||||||
|
|
||||||
// Instruct the ProtocolEngine to switch to the next stage
|
|
||||||
ProtocolEngine.previousProtocolStage();
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Switch to the next Presentation group
|
|
||||||
*
|
|
||||||
* @param event The click event on the button
|
|
||||||
*/
|
|
||||||
'click #nextPresentationGroup': function(event) {
|
|
||||||
// If no ProtocolEngine has been defined yet, do nothing
|
|
||||||
if (!ProtocolEngine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide the button's Bootstrap tooltip in case it was shown
|
|
||||||
$(event.currentTarget).tooltip('hide');
|
|
||||||
|
|
||||||
// Instruct the ProtocolEngine to switch to the next stage
|
|
||||||
ProtocolEngine.nextProtocolStage();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -6,7 +6,8 @@
|
|||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
title="Select Hanging Protocol">
|
title="Select Hanging Protocol">
|
||||||
<i class="fa fa-list-ol"></i><span class="caret"></span>
|
<i class="fa fa-list-ol"></i>
|
||||||
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li>
|
<li>
|
||||||
@ -14,7 +15,9 @@
|
|||||||
</li>
|
</li>
|
||||||
{{ #each matchedProtocols }}
|
{{ #each matchedProtocols }}
|
||||||
<li>
|
<li>
|
||||||
<a class='matchedProtocol {{#if active}}active{{/if}}'>{{name}}</a>
|
<a class='matchedProtocol {{#if active}}active{{/if}}'>
|
||||||
|
{{name}}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{{ /each }}
|
{{ /each }}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
<template name="nextPresentationGroupButton">
|
||||||
|
<div id="{{this.id}}"
|
||||||
|
class="toolbarSectionButton rp-x-1 {{this.classes}} {{activeClass}} {{ #if nextNotAvailable }}disabled{{ /if }}"
|
||||||
|
title="{{this.title}}"
|
||||||
|
disabled="{{ #if nextNotAvailable }}true{{ /if }}">
|
||||||
|
<div class="svgContainer">
|
||||||
|
{{ #if this.svgLink }}
|
||||||
|
<svg>
|
||||||
|
<use xlink:href={{this.svgLink}}></use>
|
||||||
|
</svg>
|
||||||
|
{{ else }}
|
||||||
|
<i class={{iconClasses}}></i>
|
||||||
|
{{ /if }}
|
||||||
|
</div>
|
||||||
|
<div class="buttonLabel">
|
||||||
|
{{this.title}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
Template.nextPresentationGroupButton.helpers({
|
||||||
|
/**
|
||||||
|
* Check if a later stage exists for the user to switch to
|
||||||
|
*
|
||||||
|
* @returns {boolean} Whether or not a later stage exists
|
||||||
|
*/
|
||||||
|
nextNotAvailable() {
|
||||||
|
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
||||||
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
|
// If no ProtocolEngine has been defined yet, stop here
|
||||||
|
if (!ProtocolEngine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return whether or not the current stage is the last stage
|
||||||
|
return ProtocolEngine.stage === ProtocolEngine.getNumProtocolStages() - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.nextPresentationGroupButton.events({
|
||||||
|
/**
|
||||||
|
* Switch to the next Presentation group
|
||||||
|
*
|
||||||
|
* @param event The click event on the button
|
||||||
|
*/
|
||||||
|
'click #nextPresentationGroup'(event) {
|
||||||
|
// If no ProtocolEngine has been defined yet, do nothing
|
||||||
|
if (!ProtocolEngine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the button's Bootstrap tooltip in case it was shown
|
||||||
|
$(event.currentTarget).tooltip('hide');
|
||||||
|
|
||||||
|
// Instruct the ProtocolEngine to switch to the next stage
|
||||||
|
ProtocolEngine.nextProtocolStage();
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<template name="previousPresentationGroupButton">
|
||||||
|
<div id="{{this.id}}"
|
||||||
|
class="toolbarSectionButton rp-x-1 {{this.classes}} {{activeClass}} {{ #if previousNotAvailable }}disabled{{ /if }}"
|
||||||
|
title="{{this.title}}"
|
||||||
|
disabled="{{ #if previousNotAvailable }}true{{ /if }}">
|
||||||
|
<div class="svgContainer">
|
||||||
|
{{ #if this.svgLink }}
|
||||||
|
<svg>
|
||||||
|
<use xlink:href={{this.svgLink}}></use>
|
||||||
|
</svg>
|
||||||
|
{{ else }}
|
||||||
|
<i class={{iconClasses}}></i>
|
||||||
|
{{ /if }}
|
||||||
|
</div>
|
||||||
|
<div class="buttonLabel">
|
||||||
|
{{this.title}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
Template.previousPresentationGroupButton.helpers({
|
||||||
|
/**
|
||||||
|
* Check if an earlier stage exists for the user to switch to
|
||||||
|
*
|
||||||
|
* @returns {boolean} Whether or not an earlier stage exists
|
||||||
|
*/
|
||||||
|
previousNotAvailable() {
|
||||||
|
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
||||||
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
|
// If no ProtocolEngine has been defined yet, stop here
|
||||||
|
if (!ProtocolEngine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return whether or not the current stage is the first stage
|
||||||
|
return ProtocolEngine.stage === 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.previousPresentationGroupButton.events({
|
||||||
|
/**
|
||||||
|
* Switch to the previous Presentation group
|
||||||
|
*
|
||||||
|
* @param event The click event on the button
|
||||||
|
*/
|
||||||
|
'click #previousPresentationGroup'(event) {
|
||||||
|
// If no ProtocolEngine has been defined yet, do nothing
|
||||||
|
if (!ProtocolEngine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the button's Bootstrap tooltip in case it was shown
|
||||||
|
$(event.currentTarget).tooltip('hide');
|
||||||
|
|
||||||
|
// Instruct the ProtocolEngine to switch to the next stage
|
||||||
|
ProtocolEngine.previousProtocolStage();
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -45,8 +45,11 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('client/helpers/attributes.js', 'client');
|
api.addFiles('client/helpers/attributes.js', 'client');
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
api.addFiles('client/components/hangingProtocolButtons/hangingProtocolButtons.html', 'client');
|
api.addFiles('client/components/previousPresentationGroupButton/previousPresentationGroupButton.html', 'client');
|
||||||
api.addFiles('client/components/hangingProtocolButtons/hangingProtocolButtons.js', 'client');
|
api.addFiles('client/components/previousPresentationGroupButton/previousPresentationGroupButton.js', 'client');
|
||||||
|
|
||||||
|
api.addFiles('client/components/nextPresentationGroupButton/nextPresentationGroupButton.html', 'client');
|
||||||
|
api.addFiles('client/components/nextPresentationGroupButton/nextPresentationGroupButton.js', 'client');
|
||||||
|
|
||||||
api.addFiles('client/components/matchedProtocols/matchedProtocols.html', 'client');
|
api.addFiles('client/components/matchedProtocols/matchedProtocols.html', 'client');
|
||||||
api.addFiles('client/components/matchedProtocols/matchedProtocols.styl', 'client');
|
api.addFiles('client/components/matchedProtocols/matchedProtocols.styl', 'client');
|
||||||
|
|||||||
@ -3,20 +3,20 @@
|
|||||||
// use this to repopulate the variable
|
// use this to repopulate the variable
|
||||||
ViewerData = Session.get('ViewerData') || {};
|
ViewerData = Session.get('ViewerData') || {};
|
||||||
|
|
||||||
var worklistContentId = 'worklistTab';
|
const worklistContentId = 'worklistTab';
|
||||||
var viewerContentId = 'viewerTab';
|
const viewerContentId = 'viewerTab';
|
||||||
|
|
||||||
Template.lesionTracker.onRendered(function() {
|
Template.lesionTracker.onRendered(function() {
|
||||||
var templateData = Template.currentData();
|
const templateData = Template.currentData();
|
||||||
if (templateData && templateData.studyInstanceUid) {
|
if (templateData && templateData.studyInstanceUid) {
|
||||||
var studyInstanceUid = templateData.studyInstanceUid;
|
const studyInstanceUid = templateData.studyInstanceUid;
|
||||||
openNewTab(studyInstanceUid, studyInstanceUid);
|
openNewTab(studyInstanceUid, studyInstanceUid);
|
||||||
} else {
|
} else {
|
||||||
// If there is a tab set as active in the Session,
|
// If there is a tab set as active in the Session,
|
||||||
// switch to that now.
|
// switch to that now.
|
||||||
var contentId = Session.get('activeContentId');
|
const contentId = Session.get('activeContentId');
|
||||||
|
|
||||||
// TODO: FIx this it seems to be forcing two switches
|
// TODO: Fix this it seems to be forcing two switches
|
||||||
switchToTab(contentId);
|
switchToTab(contentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ Template.lesionTracker.onRendered(function() {
|
|||||||
|
|
||||||
Template.lesionTracker.events({
|
Template.lesionTracker.events({
|
||||||
'click .js-toggle-studyList': function() {
|
'click .js-toggle-studyList': function() {
|
||||||
var contentId = Session.get('activeContentId');
|
const contentId = Session.get('activeContentId');
|
||||||
|
|
||||||
if (contentId !== worklistContentId) {
|
if (contentId !== worklistContentId) {
|
||||||
switchToTab(worklistContentId);
|
switchToTab(worklistContentId);
|
||||||
@ -39,11 +39,11 @@ Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');
|
|||||||
|
|
||||||
Template.lesionTracker.helpers({
|
Template.lesionTracker.helpers({
|
||||||
studyListToggleText: function() {
|
studyListToggleText: function() {
|
||||||
var contentId = Session.get('activeContentId');
|
const contentId = Session.get('activeContentId');
|
||||||
|
|
||||||
// If the Viewer has not been opened yet, 'Back to viewer' should
|
// If the Viewer has not been opened yet, 'Back to viewer' should
|
||||||
// not be displayed
|
// not be displayed
|
||||||
var viewerContentExists = !!Object.keys(ViewerData).length;
|
const viewerContentExists = !!Object.keys(ViewerData).length;
|
||||||
if (!viewerContentExists) {
|
if (!viewerContentExists) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,14 @@ import { OHIF } from 'meteor/ohif:core';
|
|||||||
import { TimepointApi } from 'meteor/lesiontracker/lib/api/timepoint';
|
import { TimepointApi } from 'meteor/lesiontracker/lib/api/timepoint';
|
||||||
|
|
||||||
OHIF.viewer = OHIF.viewer || {};
|
OHIF.viewer = OHIF.viewer || {};
|
||||||
|
OHIF.viewer.loadIndicatorDelay = 3000;
|
||||||
|
OHIF.viewer.defaultTool = 'wwwc';
|
||||||
|
OHIF.viewer.refLinesEnabled = true;
|
||||||
|
OHIF.viewer.isPlaying = {};
|
||||||
|
OHIF.viewer.cine = {
|
||||||
|
framesPerSecond: 24,
|
||||||
|
loop: true
|
||||||
|
};
|
||||||
|
|
||||||
Session.setDefault('activeViewport', false);
|
Session.setDefault('activeViewport', false);
|
||||||
Session.setDefault('leftSidebar', null);
|
Session.setDefault('leftSidebar', null);
|
||||||
@ -12,9 +20,6 @@ Template.viewer.onCreated(() => {
|
|||||||
|
|
||||||
instance.data.timepointApi = new TimepointApi();
|
instance.data.timepointApi = new TimepointApi();
|
||||||
|
|
||||||
// Attach the Window resize listener
|
|
||||||
$(window).on('resize', handleResize);
|
|
||||||
|
|
||||||
ValidationErrors.remove({});
|
ValidationErrors.remove({});
|
||||||
|
|
||||||
instance.data.state = new ReactiveDict();
|
instance.data.state = new ReactiveDict();
|
||||||
@ -23,49 +28,20 @@ Template.viewer.onCreated(() => {
|
|||||||
|
|
||||||
Session.set('currentTimepointId', instance.data.currentTimepointId);
|
Session.set('currentTimepointId', instance.data.currentTimepointId);
|
||||||
|
|
||||||
var contentId = instance.data.contentId;
|
const contentId = instance.data.contentId;
|
||||||
|
|
||||||
OHIF.viewer.loadIndicatorDelay = 3000;
|
OHIF.viewer.functionList = $.extend(OHIF.viewer.functionList, {
|
||||||
OHIF.viewer.defaultTool = 'wwwc';
|
|
||||||
OHIF.viewer.refLinesEnabled = true;
|
|
||||||
OHIF.viewer.isPlaying = {};
|
|
||||||
OHIF.viewer.cine = {
|
|
||||||
framesPerSecond: 24,
|
|
||||||
loop: true
|
|
||||||
};
|
|
||||||
|
|
||||||
OHIF.viewer.functionList = {
|
|
||||||
invert: function(element) {
|
|
||||||
var viewport = cornerstone.getViewport(element);
|
|
||||||
viewport.invert = !viewport.invert;
|
|
||||||
cornerstone.setViewport(element, viewport);
|
|
||||||
},
|
|
||||||
resetViewport: function(element) {
|
|
||||||
cornerstone.reset(element);
|
|
||||||
},
|
|
||||||
playClip: function(element) {
|
|
||||||
var viewportIndex = $('.imageViewerViewport').index(element);
|
|
||||||
var isPlaying = OHIF.viewer.isPlaying[viewportIndex] || false;
|
|
||||||
if (isPlaying === true) {
|
|
||||||
cornerstoneTools.stopClip(element);
|
|
||||||
} else {
|
|
||||||
cornerstoneTools.playClip(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
OHIF.viewer.isPlaying[viewportIndex] = !OHIF.viewer.isPlaying[viewportIndex];
|
|
||||||
Session.set('UpdateCINE', Random.id());
|
|
||||||
},
|
|
||||||
toggleLesionTrackerTools: toggleLesionTrackerTools,
|
toggleLesionTrackerTools: toggleLesionTrackerTools,
|
||||||
clearTools: clearTools,
|
clearTools: clearTools,
|
||||||
bidirectional: function() {
|
bidirectional: () => {
|
||||||
// Used for hotkeys
|
// Used for hotkeys
|
||||||
toolManager.setActiveTool('bidirectional');
|
toolManager.setActiveTool('bidirectional');
|
||||||
},
|
},
|
||||||
nonTarget: function() {
|
nonTarget: () => {
|
||||||
// Used for hotkeys
|
// Used for hotkeys
|
||||||
toolManager.setActiveTool('nonTarget');
|
toolManager.setActiveTool('nonTarget');
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// The hotkey can also be an array (e.g. ["NUMPAD0", "0"])
|
// The hotkey can also be an array (e.g. ["NUMPAD0", "0"])
|
||||||
OHIF.viewer.defaultHotkeys = OHIF.viewer.defaultHotkeys || {};
|
OHIF.viewer.defaultHotkeys = OHIF.viewer.defaultHotkeys || {};
|
||||||
@ -117,23 +93,23 @@ Template.viewer.onCreated(() => {
|
|||||||
// Update the ViewerStudies collection with the loaded studies
|
// Update the ViewerStudies collection with the loaded studies
|
||||||
ViewerStudies.remove({});
|
ViewerStudies.remove({});
|
||||||
|
|
||||||
instance.data.studies.forEach(function(study) {
|
instance.data.studies.forEach(study => {
|
||||||
study.selected = true;
|
study.selected = true;
|
||||||
ViewerStudies.insert(study);
|
ViewerStudies.insert(study);
|
||||||
});
|
});
|
||||||
|
|
||||||
var patientId = instance.data.studies[0].patientId;
|
const patientId = instance.data.studies[0].patientId;
|
||||||
Session.set('patientId', patientId);
|
Session.set('patientId', patientId);
|
||||||
|
|
||||||
instance.autorun(function() {
|
instance.autorun(() => {
|
||||||
var dataContext = Template.currentData();
|
const dataContext = Template.currentData();
|
||||||
instance.subscribe('singlePatientAssociatedStudies', dataContext.studies[0].patientId);
|
instance.subscribe('singlePatientAssociatedStudies', dataContext.studies[0].patientId);
|
||||||
instance.subscribe('singlePatientTimepoints', dataContext.studies[0].patientId);
|
instance.subscribe('singlePatientTimepoints', dataContext.studies[0].patientId);
|
||||||
instance.subscribe('singlePatientMeasurements', dataContext.studies[0].patientId);
|
instance.subscribe('singlePatientMeasurements', dataContext.studies[0].patientId);
|
||||||
instance.subscribe('singlePatientImageMeasurements', dataContext.studies[0].patientId);
|
instance.subscribe('singlePatientImageMeasurements', dataContext.studies[0].patientId);
|
||||||
instance.subscribe('singlePatientAdditionalFindings', dataContext.studies[0].patientId);
|
instance.subscribe('singlePatientAdditionalFindings', dataContext.studies[0].patientId);
|
||||||
|
|
||||||
var subscriptionsReady = instance.subscriptionsReady();
|
const subscriptionsReady = instance.subscriptionsReady();
|
||||||
log.info('autorun viewer.js. Ready: ' + subscriptionsReady);
|
log.info('autorun viewer.js. Ready: ' + subscriptionsReady);
|
||||||
|
|
||||||
if (subscriptionsReady) {
|
if (subscriptionsReady) {
|
||||||
@ -143,9 +119,9 @@ Template.viewer.onCreated(() => {
|
|||||||
TrialResponseCriteria.validateAllDelayed();
|
TrialResponseCriteria.validateAllDelayed();
|
||||||
|
|
||||||
ViewerStudies.find().observe({
|
ViewerStudies.find().observe({
|
||||||
added: function(study) {
|
added: study => {
|
||||||
// Find the relevant timepoint given the newly added study
|
// Find the relevant timepoint given the newly added study
|
||||||
var timepoint = Timepoints.findOne({
|
const timepoint = Timepoints.findOne({
|
||||||
studyInstanceUids: {
|
studyInstanceUids: {
|
||||||
$in: [study.studyInstanceUid]
|
$in: [study.studyInstanceUid]
|
||||||
}
|
}
|
||||||
@ -166,7 +142,7 @@ Template.viewer.onCreated(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ImageMeasurements.find().observe({
|
ImageMeasurements.find().observe({
|
||||||
added: function(data) {
|
added: data => {
|
||||||
if (data.clientId === ClientId) {
|
if (data.clientId === ClientId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -176,7 +152,7 @@ Template.viewer.onCreated(() => {
|
|||||||
// Update each displayed viewport
|
// Update each displayed viewport
|
||||||
updateAllViewports();
|
updateAllViewports();
|
||||||
},
|
},
|
||||||
changed: function(data) {
|
changed: data => {
|
||||||
if (data.clientId === ClientId) {
|
if (data.clientId === ClientId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -186,7 +162,7 @@ Template.viewer.onCreated(() => {
|
|||||||
// Update each displayed viewport
|
// Update each displayed viewport
|
||||||
updateAllViewports();
|
updateAllViewports();
|
||||||
},
|
},
|
||||||
removed: function(data) {
|
removed: data => {
|
||||||
if (data.clientId === ClientId) {
|
if (data.clientId === ClientId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -199,7 +175,7 @@ Template.viewer.onCreated(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Measurements.find().observe({
|
Measurements.find().observe({
|
||||||
added: function(data) {
|
added: data => {
|
||||||
if (data.clientId === ClientId) {
|
if (data.clientId === ClientId) {
|
||||||
TrialResponseCriteria.validateAllDelayed();
|
TrialResponseCriteria.validateAllDelayed();
|
||||||
return;
|
return;
|
||||||
@ -214,7 +190,7 @@ Template.viewer.onCreated(() => {
|
|||||||
// Update each displayed viewport
|
// Update each displayed viewport
|
||||||
updateAllViewports();
|
updateAllViewports();
|
||||||
},
|
},
|
||||||
changed: function(data) {
|
changed: data => {
|
||||||
if (data.clientId === ClientId) {
|
if (data.clientId === ClientId) {
|
||||||
TrialResponseCriteria.validateAllDelayed();
|
TrialResponseCriteria.validateAllDelayed();
|
||||||
return;
|
return;
|
||||||
@ -231,7 +207,7 @@ Template.viewer.onCreated(() => {
|
|||||||
|
|
||||||
TrialResponseCriteria.validateAllDelayed();
|
TrialResponseCriteria.validateAllDelayed();
|
||||||
},
|
},
|
||||||
removed: function(data) {
|
removed: data => {
|
||||||
log.info('Measurement removed');
|
log.info('Measurement removed');
|
||||||
|
|
||||||
// Check that this Measurement actually contains timepoint data
|
// Check that this Measurement actually contains timepoint data
|
||||||
@ -241,14 +217,14 @@ Template.viewer.onCreated(() => {
|
|||||||
|
|
||||||
// Get the Measurement ID and relevant tool so we can remove
|
// Get the Measurement ID and relevant tool so we can remove
|
||||||
// tool data for this Measurement
|
// tool data for this Measurement
|
||||||
var measurementId = data._id;
|
const measurementId = data._id;
|
||||||
var toolType = data.toolType;
|
const toolType = data.toolType;
|
||||||
|
|
||||||
// Remove the measurement from all the imageIds on which it exists
|
// Remove the measurement from all the imageIds on which it exists
|
||||||
// as toolData
|
// as toolData
|
||||||
Object.keys(data.timepoints).forEach(function(timepointId) {
|
Object.keys(data.timepoints).forEach(timepointId => {
|
||||||
// Clear the toolData for this timepoint
|
// Clear the toolData for this timepoint
|
||||||
var imageId = data.timepoints[timepointId].imageId;
|
const imageId = data.timepoints[timepointId].imageId;
|
||||||
removeToolDataWithMeasurementId(imageId, toolType, measurementId);
|
removeToolDataWithMeasurementId(imageId, toolType, measurementId);
|
||||||
|
|
||||||
// Set reviewer for this timepoint
|
// Set reviewer for this timepoint
|
||||||
@ -264,14 +240,14 @@ Template.viewer.onCreated(() => {
|
|||||||
// find the Measurements, whereas on the server it's
|
// find the Measurements, whereas on the server it's
|
||||||
// only "greater than", since inside this callback the
|
// only "greater than", since inside this callback the
|
||||||
// Measurements have already been decremented.
|
// Measurements have already been decremented.
|
||||||
var measurements = Measurements.find({
|
const measurements = Measurements.find({
|
||||||
patientId: data.patientId,
|
patientId: data.patientId,
|
||||||
lesionNumberAbsolute: {
|
lesionNumberAbsolute: {
|
||||||
$gte: data.lesionNumberAbsolute
|
$gte: data.lesionNumberAbsolute
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
measurements.forEach(function(measurement) {
|
measurements.forEach(measurement => {
|
||||||
syncMeasurementAndToolData(measurement);
|
syncMeasurementAndToolData(measurement);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -289,26 +265,14 @@ Template.viewer.onCreated(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.viewer.onRendered(function() {
|
|
||||||
// Enable hotkeys
|
|
||||||
enableHotkeys();
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.viewer.onDestroyed(function() {
|
|
||||||
// Remove the Window resize listener
|
|
||||||
$(window).off('resize', handleResize);
|
|
||||||
|
|
||||||
OHIF.viewer.updateImageSynchronizer.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.viewer.events({
|
Template.viewer.events({
|
||||||
'CornerstoneToolsMeasurementAdded .imageViewerViewport': function(e, template, eventData) {
|
'CornerstoneToolsMeasurementAdded .imageViewerViewport'(event, instance, eventData) {
|
||||||
handleMeasurementAdded(e, eventData);
|
handleMeasurementAdded(event, eventData);
|
||||||
},
|
},
|
||||||
'CornerstoneToolsMeasurementModified .imageViewerViewport': function(e, template, eventData) {
|
'CornerstoneToolsMeasurementModified .imageViewerViewport'(event, instance, eventData) {
|
||||||
handleMeasurementModified(e, eventData);
|
handleMeasurementModified(event, eventData);
|
||||||
},
|
},
|
||||||
'CornerstoneToolsMeasurementRemoved .imageViewerViewport': function(e, template, eventData) {
|
'CornerstoneToolsMeasurementRemoved .imageViewerViewport'(event, instance, eventData) {
|
||||||
handleMeasurementRemoved(e, eventData);
|
handleMeasurementRemoved(event, eventData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,41 +1,47 @@
|
|||||||
<template name="cineDialog">
|
<template name="cineDialog">
|
||||||
<div id="cineDialog">
|
<div id="cineDialog" class="noselect">
|
||||||
<h5>Cine Controls</h5>
|
<h5>CINE Controls</h5>
|
||||||
<div id="cineButtons">
|
<div class="btn-group">
|
||||||
<a id="cineFirstButton" title="Skip to first image" class="cineButton" data-toggle="tooltip">
|
<a id="cineFirstButton" title="Skip to first image" class="btn" data-toggle="tooltip">
|
||||||
<i class="fa fa-lg fa-fast-backward"></i>
|
<i class="fa fa-fast-backward"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="cineBackButton" title="Previous image" class="cineButton" data-toggle="tooltip">
|
<a id="cineBackButton" title="Previous image" class="btn" data-toggle="tooltip">
|
||||||
<i class="fa fa-lg fa-step-backward"></i>
|
<i class="fa fa-step-backward"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="cineSlowPlaybackButton" title="Slow playback" class="cineButton" data-toggle="tooltip">
|
<a id="cineSlowPlaybackButton" title="Slow playback" class="btn" data-toggle="tooltip">
|
||||||
<i class="fa fa-lg fa-backward"></i>
|
<i class="fa fa-backward"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="cinePlayButton" title="Play / Pause" class="cineButton" data-toggle="tooltip">
|
<a id="cinePlayButton" title="Play / Stop" class="btn {{#if isPlaying}}active{{/if}}" data-toggle="tooltip">
|
||||||
{{#if isPlaying}}
|
{{#if isPlaying}}
|
||||||
<i class="fa fa-lg fa-pause"></i>
|
<i class="fa fa-fw fa-stop"></i>
|
||||||
{{else}}
|
{{else}}
|
||||||
<i class="fa fa-lg fa-play"></i>
|
<i class="fa fa-fw fa-play"></i>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</a>
|
</a>
|
||||||
<a id="cineFastForwardButton" title="Increase playback speed" class="cineButton" data-toggle="tooltip">
|
<a id="cineFastForwardButton" title="Increase playback speed" class="btn" data-toggle="tooltip">
|
||||||
<i class="fa fa-lg fa-forward"></i>
|
<i class="fa fa-forward"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="cineNextButton" title="Next image" class="cineButton" data-toggle="tooltip">
|
<a id="cineNextButton" title="Next image" class="btn" data-toggle="tooltip">
|
||||||
<i class="fa fa-lg fa-step-forward"></i>
|
<i class="fa fa-step-forward"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="cineLastButton" title="Skip to last image" class="cineButton" data-toggle="tooltip">
|
<a id="cineLastButton" title="Skip to last image" class="btn" data-toggle="tooltip">
|
||||||
<i class="fa fa-lg fa-fast-forward"></i>
|
<i class="fa fa-fast-forward"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="cineOptions">
|
<div id="cineOptions">
|
||||||
<div id="loopSection">
|
<div id="loopSection">
|
||||||
<label>Loop?</label>
|
<label for="cineLoopCheckbox">Loop?</label>
|
||||||
<input type="checkbox" checked id="cineLoopCheckbox" />
|
<input type="checkbox" checked id="cineLoopCheckbox" />
|
||||||
</div>
|
</div>
|
||||||
<div id="fpsSection">
|
<div id="fpsSection">
|
||||||
<label>Cine Speed: <span id="fps">{{framerate}}</span></label>
|
<label for="cineSlider">
|
||||||
<input type="range" id="cineSlider" min="1" max="90" value="{{framerate}}"/>
|
Cine Speed: <span id="fps">{{framerate}}</span>
|
||||||
|
</label>
|
||||||
|
<input type="range"
|
||||||
|
id="cineSlider"
|
||||||
|
min="1"
|
||||||
|
max="90"
|
||||||
|
value="{{framerate}}"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,16 +1,5 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
toggleCinePlay = function() {
|
|
||||||
var element = getActiveViewportElement();
|
|
||||||
var playClipToolData = cornerstoneTools.getToolState(element, 'playClip');
|
|
||||||
|
|
||||||
if (isPlaying()) {
|
|
||||||
cornerstoneTools.stopClip(element);
|
|
||||||
} else {
|
|
||||||
cornerstoneTools.playClip(element);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function updateFramerate(rate) {
|
function updateFramerate(rate) {
|
||||||
OHIF.viewer.cine.framesPerSecond = rate;
|
OHIF.viewer.cine.framesPerSecond = rate;
|
||||||
|
|
||||||
@ -74,6 +63,7 @@ Template.cineDialog.events({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Template.cineDialog.onRendered(function() {
|
Template.cineDialog.onRendered(function() {
|
||||||
var dialog = $('#cineDialog');
|
const instance = Template.instance();
|
||||||
|
const dialog = instance.$('#cineDialog');
|
||||||
dialog.draggable();
|
dialog.draggable();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
@import "{design}/app.styl"
|
||||||
|
|
||||||
|
$borderColor = rgba(77, 99, 110, 0.81)
|
||||||
|
|
||||||
#cineDialog
|
#cineDialog
|
||||||
display: none
|
display: none
|
||||||
z-index: 1000
|
z-index: 1000
|
||||||
@ -9,32 +13,29 @@
|
|||||||
|
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
padding: 10px
|
padding: 10px
|
||||||
|
width: 300px
|
||||||
width: 250px
|
|
||||||
height: 175px
|
height: 175px
|
||||||
|
|
||||||
border: 1px black solid
|
opacity: 0.95
|
||||||
border-radius: 3px
|
border-radius: 8px
|
||||||
background: white
|
border: 1px solid $borderColor;
|
||||||
color: black
|
background: $uiGrayDarkest
|
||||||
|
color: $textSecondaryColor
|
||||||
|
|
||||||
|
h5, label
|
||||||
|
font-weight: 100
|
||||||
|
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
|
|
||||||
-webkit-user-select: none
|
.btn
|
||||||
-moz-user-select: none
|
background: $uiGrayDarkest
|
||||||
-o-user-select: none
|
color: $textSecondaryColor
|
||||||
-ms-user-select: none
|
|
||||||
-khtml-user-select: none
|
|
||||||
user-select: none
|
|
||||||
|
|
||||||
#cineButtons
|
&:hover
|
||||||
padding-bottom: 10px
|
color: $hoverColor
|
||||||
overflow: auto
|
|
||||||
|
|
||||||
.cineButton
|
&:active, &.active
|
||||||
cursor: pointer
|
color: $activeColor
|
||||||
margin: 0 6px
|
|
||||||
text-decoration: none
|
|
||||||
|
|
||||||
#cineOptions
|
#cineOptions
|
||||||
padding: 5px 0
|
padding: 5px 0
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
<template name="layoutButton">
|
||||||
|
<div id="{{this.id}}"
|
||||||
|
class="toolbarSectionButton rp-x-1 {{this.classes}} {{activeClass}} js-dropdown-toggle"
|
||||||
|
title="{{this.title}}"
|
||||||
|
data-target="#layoutChooser"
|
||||||
|
>
|
||||||
|
<div class="svgContainer">
|
||||||
|
{{ #if this.svgLink }}
|
||||||
|
<svg>
|
||||||
|
<use xlink:href={{this.svgLink}}></use>
|
||||||
|
</svg>
|
||||||
|
{{ else }}
|
||||||
|
<i class={{iconClasses}}></i>
|
||||||
|
{{ /if }}
|
||||||
|
</div>
|
||||||
|
<div class="buttonLabel">
|
||||||
|
{{this.title}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
Template.layoutButton.events({
|
||||||
|
// TODO: Check why 'click' event won't fire?
|
||||||
|
'mousedown .js-dropdown-toggle'(event) {
|
||||||
|
// Select the button and it's target dropdown menu
|
||||||
|
const $button = $(event.currentTarget);
|
||||||
|
const $dropdown = $($button.data('target'));
|
||||||
|
|
||||||
|
// Adjust the dropdown's CSS to properly place it on the page
|
||||||
|
$dropdown.css({
|
||||||
|
top: $button.offset().top + $button.outerHeight() + 'px',
|
||||||
|
left: $button.offset().left + 'px'
|
||||||
|
});
|
||||||
|
|
||||||
|
toggleDialog($dropdown);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template name="layoutChooser">
|
<template name="layoutChooser">
|
||||||
<div class="layoutChooser pull-left dropdown-menu" role="menu">
|
<div id="layoutChooser" class="layoutChooser pull-left dropdown-menu" role="menu">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
|||||||
@ -6,39 +6,41 @@
|
|||||||
* @param currentCell
|
* @param currentCell
|
||||||
*/
|
*/
|
||||||
function highlightCells(currentCell) {
|
function highlightCells(currentCell) {
|
||||||
var cells = $('.layoutChooser table td');
|
const cells = $('.layoutChooser table td');
|
||||||
cells.removeClass('hover');
|
cells.removeClass('hover');
|
||||||
|
|
||||||
currentCell = $(currentCell);
|
currentCell = $(currentCell);
|
||||||
var table = currentCell.parents('.layoutChooser table').get(0);
|
const table = currentCell.parents('.layoutChooser table').get(0);
|
||||||
var rowIndex = currentCell.closest('tr').index();
|
const rowIndex = currentCell.closest('tr').index();
|
||||||
var columnIndex = currentCell.index();
|
const columnIndex = currentCell.index();
|
||||||
|
|
||||||
// Loop through the table row by row
|
// Loop through the table row by row
|
||||||
// and cell by cell to apply the highlighting
|
// and cell by cell to apply the highlighting
|
||||||
for (var i = 0; i < table.rows.length; i++) {
|
for (var i = 0; i < table.rows.length; i++) {
|
||||||
row = table.rows[i];
|
const row = table.rows[i];
|
||||||
if (i <= rowIndex) {
|
if (i <= rowIndex) {
|
||||||
for (var j = 0; j < row.cells.length; j++) {
|
for (var j = 0; j < row.cells.length; j++) {
|
||||||
if (j <= columnIndex) {
|
if (j <= columnIndex) {
|
||||||
cell = row.cells[j];
|
const cell = row.cells[j];
|
||||||
cell.classList.add('hover');
|
cell.classList.add('hover');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Template.layoutChooser.events({
|
Template.layoutChooser.events({
|
||||||
'touchstart .layoutChooser table td, mouseenter .layoutChooser table td': function(evt) {
|
'touchstart .layoutChooser table td, mouseenter .layoutChooser table td'(evt) {
|
||||||
highlightCells(evt.currentTarget);
|
highlightCells(evt.currentTarget);
|
||||||
},
|
},
|
||||||
'click .layoutChooser table td': function(evt) {
|
|
||||||
var currentCell = $(evt.currentTarget);
|
'click .layoutChooser table td'(evt) {
|
||||||
var rowIndex = currentCell.closest('tr').index();
|
const currentCell = $(evt.currentTarget);
|
||||||
var columnIndex = currentCell.index();
|
const rowIndex = currentCell.closest('tr').index();
|
||||||
|
const columnIndex = currentCell.index();
|
||||||
|
|
||||||
// Add 1 because the indices start from zero
|
// Add 1 because the indices start from zero
|
||||||
var layoutProps = {
|
const layoutProps = {
|
||||||
rows: rowIndex + 1,
|
rows: rowIndex + 1,
|
||||||
columns: columnIndex + 1
|
columns: columnIndex + 1
|
||||||
};
|
};
|
||||||
@ -46,5 +48,8 @@ Template.layoutChooser.events({
|
|||||||
layoutManager.layoutTemplateName = 'gridLayout';
|
layoutManager.layoutTemplateName = 'gridLayout';
|
||||||
layoutManager.layoutProps = layoutProps;
|
layoutManager.layoutProps = layoutProps;
|
||||||
layoutManager.updateViewports();
|
layoutManager.updateViewports();
|
||||||
|
|
||||||
|
const $dropdown = $('.layoutChooser');
|
||||||
|
toggleDialog($dropdown);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1,19 +1,28 @@
|
|||||||
@import "{design}/app.styl"
|
@import "{design}/app.styl"
|
||||||
|
|
||||||
|
$borderColor = rgba(77, 99, 110, 0.81)
|
||||||
|
|
||||||
.layoutChooser
|
.layoutChooser
|
||||||
width: 92px
|
width: 92px
|
||||||
height: 92px
|
height: 92px
|
||||||
min-width: 92px // to override bootstrap's dropdown-menu class
|
min-width: 92px // to override bootstrap's dropdown-menu class
|
||||||
min-height: 92px
|
min-height: 92px
|
||||||
background-color: $primaryBackgroundColor
|
|
||||||
border: 2px solid $uiBorderColorDark
|
//background-color: $primaryBackgroundColor
|
||||||
|
opacity: 0.95
|
||||||
|
border-radius: 8px
|
||||||
|
border: 1px solid $borderColor;
|
||||||
|
background: $uiGrayDarkest
|
||||||
|
|
||||||
|
&.open
|
||||||
|
display: block
|
||||||
|
|
||||||
table
|
table
|
||||||
margin: 0 auto
|
margin: 0 auto
|
||||||
|
|
||||||
td
|
td
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
border: 2px solid $uiBorderColorDark
|
border: 1px solid $uiBorderColorDark
|
||||||
width: 20px
|
width: 20px
|
||||||
height: 20px
|
height: 20px
|
||||||
transition(background-color 0.1s ease)
|
transition(background-color 0.1s ease)
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
p, h4
|
p, h4
|
||||||
text-align: center
|
text-align: center
|
||||||
color: $textColorActive
|
color: $textColorActive
|
||||||
padding: 4px 0px
|
padding: 4px 0
|
||||||
|
|
||||||
p
|
p
|
||||||
font-size: 11pt
|
font-size: 11pt
|
||||||
|
|||||||
@ -1,24 +1,20 @@
|
|||||||
<template name="playClipButton">
|
<template name="playClipButton">
|
||||||
<button id="playClip"
|
<div id="{{this.id}}"
|
||||||
type="button"
|
class="toolbarSectionButton rp-x-1 {{this.classes}} {{activeClass}} {{ #if isPlaying }}active{{/if}}"
|
||||||
class="imageViewerCommand btn btn-sm {{ #if isPlaying }}active{{/if}}"
|
title="{{this.title}}">
|
||||||
data-container="body"
|
<div class="svgContainer">
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="bottom"
|
|
||||||
title="Play/Stop Clip">
|
|
||||||
{{ #if isPlaying }}
|
{{ #if isPlaying }}
|
||||||
<span class="fa fa-stop"></span>
|
<i class="fa fa-stop fa-fw"></i>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<span class="fa fa-play"></span>
|
<i class="fa fa-play fa-fw"></i>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
</button>
|
</div>
|
||||||
<button id="toggleCineDialog"
|
<div class="buttonLabel">
|
||||||
type="button"
|
{{ #if isPlaying }}
|
||||||
class="imageViewerCommand btn btn-sm"
|
Stop
|
||||||
data-container="body"
|
{{ else }}
|
||||||
data-toggle="tooltip"
|
Play
|
||||||
data-placement="bottom"
|
{{/if}}
|
||||||
title="Toggle CINE Dialog">
|
</div>
|
||||||
<span class="fa fa-youtube-play"></span>
|
</div>
|
||||||
</button>
|
|
||||||
</template>
|
</template>
|
||||||
@ -1,54 +1,5 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
|
|
||||||
toggleCinePlay = function(element) {
|
|
||||||
var viewports = $('.imageViewerViewport');
|
|
||||||
|
|
||||||
if (!element) {
|
|
||||||
var viewportIndex = Session.get('activeViewport');
|
|
||||||
element = viewports.get(viewportIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!element) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isPlaying = OHIF.viewer.isPlaying[viewportIndex] || false;
|
|
||||||
if (isPlaying) {
|
|
||||||
cornerstoneTools.stopClip(element);
|
|
||||||
} else {
|
|
||||||
cornerstoneTools.playClip(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
OHIF.viewer.isPlaying[viewportIndex] = !OHIF.viewer.isPlaying[viewportIndex];
|
|
||||||
Session.set('UpdateCINE', Random.id());
|
|
||||||
};
|
|
||||||
|
|
||||||
isPlaying = function() {
|
|
||||||
Session.get('UpdateCINE');
|
|
||||||
var activeViewport = Session.get('activeViewport');
|
|
||||||
|
|
||||||
// TODO=Check best way to make sure this is always defined
|
|
||||||
// Right now it is initialized in enableHotkeys AND in
|
|
||||||
// imageViewer onCreated, but this appears to break some things
|
|
||||||
if (!OHIF.viewer.isPlaying) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!OHIF.viewer.isPlaying[activeViewport];
|
|
||||||
};
|
|
||||||
|
|
||||||
Template.playClipButton.helpers({
|
Template.playClipButton.helpers({
|
||||||
isPlaying: function() {
|
isPlaying: function() {
|
||||||
return isPlaying();
|
return isPlaying();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.playClipButton.events({
|
|
||||||
'click #playClip': function() {
|
|
||||||
toggleCinePlay();
|
|
||||||
},
|
|
||||||
'click #toggleCineDialog': function() {
|
|
||||||
var cineDialog = document.getElementById('cineDialog');
|
|
||||||
toggleDialog(cineDialog);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
<template name="simpleToolbarButton">
|
|
||||||
<button id="{{id}}"
|
|
||||||
type="button"
|
|
||||||
class="{{classes}} btn btn-sm {{activeClass}}"
|
|
||||||
data-container="body"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="bottom"
|
|
||||||
title="{{title}}">
|
|
||||||
<span class="{{iconClasses}}"></span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
Template.simpleToolbarButton.helpers({
|
|
||||||
activeClass() {
|
|
||||||
const instance = Template.instance();
|
|
||||||
|
|
||||||
// Check if the current tool is the active one
|
|
||||||
if (instance.data.id === Session.get('ToolManagerActiveTool')) {
|
|
||||||
// Return the active class
|
|
||||||
return 'active';
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
<template name="toolbar">
|
|
||||||
<div class="btn-group">
|
|
||||||
{{ #each button }}
|
|
||||||
{{ >simpleToolbarButton}}
|
|
||||||
{{ /each }}
|
|
||||||
|
|
||||||
{{ #if includePlayClipButton }}
|
|
||||||
{{ >playClipButton }}
|
|
||||||
{{ /if }}
|
|
||||||
|
|
||||||
{{ #if includeLayoutButton }}
|
|
||||||
<div class="btn-group">
|
|
||||||
<button id="layout"
|
|
||||||
type="button"
|
|
||||||
class="btn btn-sm dropdown-toggle"
|
|
||||||
data-container="body"
|
|
||||||
data-toggle="dropdown"
|
|
||||||
aria-expanded="false"
|
|
||||||
data-placement="right"
|
|
||||||
title="Layout"
|
|
||||||
rel="tooltip">
|
|
||||||
<span class="fa fa-th-large"></span>
|
|
||||||
</button>
|
|
||||||
{{ >layoutChooser }}
|
|
||||||
</div>
|
|
||||||
{{ /if }}
|
|
||||||
|
|
||||||
{{ #if includeHangingProtocolButtons }}
|
|
||||||
{{ >hangingProtocolButtons }}
|
|
||||||
{{ >matchedProtocols }}
|
|
||||||
{{ /if }}
|
|
||||||
|
|
||||||
{{ #each btnGroup }}
|
|
||||||
{{ >toolbarGroupButton}}
|
|
||||||
{{ /each }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@ -1,205 +0,0 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
|
|
||||||
function getDefaultButtonData() {
|
|
||||||
var buttonData = [];
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'wwwc',
|
|
||||||
title: 'WW/WC',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-sun-o'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'wwwcRegion',
|
|
||||||
title: 'Window by Region',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-square'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'magnify',
|
|
||||||
title: 'Magnify',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-circle'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'annotate',
|
|
||||||
title: 'Annotation',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-arrows-h'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'invert',
|
|
||||||
title: 'Invert',
|
|
||||||
classes: 'imageViewerCommand',
|
|
||||||
iconClasses: 'fa fa-adjust'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'zoom',
|
|
||||||
title: 'Zoom',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-search'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'pan',
|
|
||||||
title: 'Pan',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-arrows'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'stackScroll',
|
|
||||||
title: 'Stack Scroll',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-bars'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'length',
|
|
||||||
title: 'Length Measurement',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-arrows-v'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'angle',
|
|
||||||
title: 'Angle Measurement',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-angle-left'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'dragProbe',
|
|
||||||
title: 'Pixel Probe',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-dot-circle-o'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'ellipticalRoi',
|
|
||||||
title: 'Elliptical ROI',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-circle-o'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'rectangleRoi',
|
|
||||||
title: 'Rectangle ROI',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-square-o'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'resetViewport',
|
|
||||||
title: 'Reset Viewport',
|
|
||||||
classes: 'imageViewerCommand',
|
|
||||||
iconClasses: 'fa fa-undo'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'clearTools',
|
|
||||||
title: 'Clear tools',
|
|
||||||
classes: 'imageViewerCommand',
|
|
||||||
iconClasses: 'fa fa-trash'
|
|
||||||
});
|
|
||||||
return buttonData;
|
|
||||||
}
|
|
||||||
|
|
||||||
Template.toolbar.events({
|
|
||||||
'click .imageViewerTool': function(e) {
|
|
||||||
$(e.currentTarget).tooltip('hide');
|
|
||||||
|
|
||||||
var tool = e.currentTarget.id;
|
|
||||||
|
|
||||||
var elements = $('.imageViewerViewport');
|
|
||||||
|
|
||||||
var activeTool = toolManager.getActiveTool();
|
|
||||||
if (tool === activeTool) {
|
|
||||||
var defaultTool = toolManager.getDefaultTool();
|
|
||||||
console.log('Setting active tool to: ' + defaultTool);
|
|
||||||
toolManager.setActiveTool(defaultTool, elements);
|
|
||||||
} else {
|
|
||||||
console.log('Setting active tool to: ' + tool);
|
|
||||||
toolManager.setActiveTool(tool, elements);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .imageViewerCommand': function(e) {
|
|
||||||
$(e.currentTarget).tooltip('hide');
|
|
||||||
|
|
||||||
var command = e.currentTarget.id;
|
|
||||||
if (!OHIF.viewer.functionList.hasOwnProperty(command)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var activeViewport = Session.get('activeViewport');
|
|
||||||
var element = $('.imageViewerViewport').get(activeViewport);
|
|
||||||
OHIF.viewer.functionList[command](element);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.toolbar.onRendered(function() {
|
|
||||||
var tooltipButtons = $('[data-toggle="tooltip"]');
|
|
||||||
tooltipButtons.tooltip(OHIF.viewer.tooltipConfig);
|
|
||||||
|
|
||||||
// Enable tooltips for the layout button
|
|
||||||
var extraTooltipButtons = $('[rel="tooltip"]');
|
|
||||||
extraTooltipButtons.tooltip(OHIF.viewer.tooltipConfig);
|
|
||||||
|
|
||||||
// Set disabled/enabled tool buttons that are set in toolManager
|
|
||||||
var states = toolManager.getToolDefaultStates();
|
|
||||||
var disabledToolButtons = states.disabledToolButtons;
|
|
||||||
var allToolbarButtons = $('#toolbar').find('button');
|
|
||||||
if (disabledToolButtons && disabledToolButtons.length > 0) {
|
|
||||||
for (var i = 0; i < allToolbarButtons.length; i++) {
|
|
||||||
var toolbarButton = allToolbarButtons[i];
|
|
||||||
$(toolbarButton).prop('disabled', false);
|
|
||||||
var index = disabledToolButtons.indexOf($(toolbarButton).attr('id'));
|
|
||||||
if (index !== -1) {
|
|
||||||
$(toolbarButton).prop('disabled', true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.toolbar.helpers({
|
|
||||||
button: function() {
|
|
||||||
if (this.toolbarOptions && this.toolbarOptions.buttonData) {
|
|
||||||
return this.toolbarOptions.buttonData;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getDefaultButtonData();
|
|
||||||
},
|
|
||||||
includePlayClipButton: function() {
|
|
||||||
if (this.toolbarOptions && this.toolbarOptions.includePlayClipButton !== undefined) {
|
|
||||||
return this.toolbarOptions.includePlayClipButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
includeLayoutButton: function() {
|
|
||||||
if (this.toolbarOptions && this.toolbarOptions.includeLayoutButton !== undefined) {
|
|
||||||
return this.toolbarOptions.includeLayoutButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
includeHangingProtocolButtons: function() {
|
|
||||||
if (this.toolbarOptions && this.toolbarOptions.includeHangingProtocolButtons !== undefined) {
|
|
||||||
return this.toolbarOptions.includeHangingProtocolButtons;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
btnGroup: function() {
|
|
||||||
if (this.toolbarOptions && this.toolbarOptions.btnGroup !== undefined) {
|
|
||||||
return this.toolbarOptions.btnGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
@import "{design}/app.styl"
|
|
||||||
|
|
||||||
.btn-group
|
|
||||||
background-color: $primaryBackgroundColor
|
|
||||||
display: inline-block
|
|
||||||
|
|
||||||
button
|
|
||||||
text-align: center
|
|
||||||
color: $defaultColor
|
|
||||||
background-color: $primaryBackgroundColor
|
|
||||||
border-color: $uiBorderColor
|
|
||||||
transition(all 0.1s ease)
|
|
||||||
|
|
||||||
// Prevent the blue outline in Chrome when a viewport is selected
|
|
||||||
outline: 0 !important
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
color: $hoverColor
|
|
||||||
|
|
||||||
&.active, &:active
|
|
||||||
color: $activeColor
|
|
||||||
@ -1,5 +1,10 @@
|
|||||||
<template name="toolbarSectionButton">
|
<template name="toolbarSectionButton">
|
||||||
<div id="{{this.id}}" class="toolbarSectionButton rp-x-1 {{this.classes}} {{activeClass}}" title="{{this.title}}">
|
{{ #if this.buttonTemplateName }}
|
||||||
|
{{> UI.dynamic template=this.buttonTemplateName data=this }}
|
||||||
|
{{ else }}
|
||||||
|
<div id="{{this.id}}"
|
||||||
|
class="toolbarSectionButton rp-x-1 {{this.classes}} {{activeClass}}"
|
||||||
|
title="{{this.title}}">
|
||||||
<div class="svgContainer">
|
<div class="svgContainer">
|
||||||
{{ #if this.svgLink }}
|
{{ #if this.svgLink }}
|
||||||
<svg>
|
<svg>
|
||||||
@ -13,4 +18,5 @@
|
|||||||
{{this.title}}
|
{{this.title}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ /if }}
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -30,7 +30,7 @@ Template.toolbarSectionButton.events({
|
|||||||
},
|
},
|
||||||
'click .imageViewerCommand'(event, instance) {
|
'click .imageViewerCommand'(event, instance) {
|
||||||
const command = event.currentTarget.id;
|
const command = event.currentTarget.id;
|
||||||
if (!OHIF.viewer.functionList.hasOwnProperty(command)) {
|
if (!OHIF.viewer.functionList || !OHIF.viewer.functionList.hasOwnProperty(command)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
{{>toolbarSectionButton toolbarButton}}
|
{{>toolbarSectionButton toolbarButton}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
|
{{ #if extraToolbarButtons}}
|
||||||
<div id="moreTools" class="js-open-more-tools toolbarSectionButton rp-x-1 rm-l-3">
|
<div id="moreTools" class="js-open-more-tools toolbarSectionButton rp-x-1 rm-l-3">
|
||||||
<div class="svgContainer">
|
<div class="svgContainer">
|
||||||
<svg>
|
<svg>
|
||||||
@ -24,5 +25,6 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ /if }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -1,10 +1,26 @@
|
|||||||
Template.viewerMain.onRendered(function() {
|
Template.viewerMain.onCreated(() => {
|
||||||
var instance = this;
|
// Attach the Window resize listener
|
||||||
var studies = instance.data.studies;
|
$(window).on('resize', handleResize);
|
||||||
|
});
|
||||||
|
|
||||||
var parentElement = instance.$("#layoutManagerTarget").get(0);
|
Template.viewerMain.onRendered(() => {
|
||||||
|
const instance = Template.instance();
|
||||||
|
|
||||||
|
const studies = instance.data.studies;
|
||||||
|
const parentElement = instance.$("#layoutManagerTarget").get(0);
|
||||||
window.layoutManager = new LayoutManager(parentElement, studies);
|
window.layoutManager = new LayoutManager(parentElement, studies);
|
||||||
|
|
||||||
ProtocolEngine = new HP.ProtocolEngine(window.layoutManager, studies);
|
ProtocolEngine = new HP.ProtocolEngine(window.layoutManager, studies);
|
||||||
HP.setEngine(ProtocolEngine);
|
HP.setEngine(ProtocolEngine);
|
||||||
|
|
||||||
|
// Enable hotkeys
|
||||||
|
enableHotkeys();
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.viewerMain.onDestroyed(() => {
|
||||||
|
// Remove the Window resize listener
|
||||||
|
$(window).off('resize', handleResize);
|
||||||
|
|
||||||
|
// Destory the synchronizer used to update reference lines
|
||||||
|
OHIF.viewer.updateImageSynchronizer.destroy();
|
||||||
});
|
});
|
||||||
@ -5,8 +5,8 @@
|
|||||||
* @param {Object} study The study instance
|
* @param {Object} study The study instance
|
||||||
*/
|
*/
|
||||||
sortStudy = function(study) {
|
sortStudy = function(study) {
|
||||||
if (!study) {
|
if (!study || !study.seriesList) {
|
||||||
return;
|
throw "Insufficient study data was provided to sortStudy";
|
||||||
}
|
}
|
||||||
|
|
||||||
study.seriesList.sort(function(a, b) {
|
study.seriesList.sort(function(a, b) {
|
||||||
|
|||||||
@ -4,65 +4,120 @@ getActiveViewportElement = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
zoomIn = function() {
|
zoomIn = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
var viewport = cornerstone.getViewport(element);
|
let viewport = cornerstone.getViewport(element);
|
||||||
viewport.scale += 0.15;
|
const scaleIncrement = 0.15;
|
||||||
if (viewport.scale > 10.0) {
|
const maximumScale = 10;
|
||||||
viewport.scale = 10.0;
|
viewport.scale = Math.min(viewport.scale + increment, maximumScale);
|
||||||
}
|
|
||||||
cornerstone.setViewport(element, viewport);
|
cornerstone.setViewport(element, viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
zoomOut = function() {
|
zoomOut = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
var viewport = cornerstone.getViewport(element);
|
let viewport = cornerstone.getViewport(element);
|
||||||
viewport.scale -= 0.15;
|
const scaleIncrement = 0.15;
|
||||||
if (viewport.scale < 0.05) {
|
const minimumScale = 0.05;
|
||||||
viewport.scale = 0.05;
|
viewport.scale = Math.max(viewport.scale - increment, minimumScale);
|
||||||
}
|
|
||||||
cornerstone.setViewport(element, viewport);
|
cornerstone.setViewport(element, viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
zoomToFit = function() {
|
zoomToFit = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
cornerstone.fitToWindow(element);
|
cornerstone.fitToWindow(element);
|
||||||
};
|
};
|
||||||
|
|
||||||
rotateL = function() {
|
rotateL = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
var viewport = cornerstone.getViewport(element);
|
let viewport = cornerstone.getViewport(element);
|
||||||
viewport.rotation -= 90;
|
viewport.rotation -= 90;
|
||||||
cornerstone.setViewport(element, viewport);
|
cornerstone.setViewport(element, viewport);
|
||||||
updateOrientationMarkers(element, viewport);
|
updateOrientationMarkers(element, viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
rotateR = function() {
|
rotateR = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
var viewport = cornerstone.getViewport(element);
|
let viewport = cornerstone.getViewport(element);
|
||||||
viewport.rotation += 90;
|
viewport.rotation += 90;
|
||||||
cornerstone.setViewport(element, viewport);
|
cornerstone.setViewport(element, viewport);
|
||||||
updateOrientationMarkers(element, viewport);
|
updateOrientationMarkers(element, viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
invert = function() {
|
invert = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
var viewport = cornerstone.getViewport(element);
|
let viewport = cornerstone.getViewport(element);
|
||||||
viewport.invert = (viewport.invert === false);
|
viewport.invert = (viewport.invert === false);
|
||||||
cornerstone.setViewport(element, viewport);
|
cornerstone.setViewport(element, viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
flipV = function() {
|
flipV = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
var viewport = cornerstone.getViewport(element);
|
let viewport = cornerstone.getViewport(element);
|
||||||
viewport.vflip = (viewport.vflip === false);
|
viewport.vflip = (viewport.vflip === false);
|
||||||
cornerstone.setViewport(element, viewport);
|
cornerstone.setViewport(element, viewport);
|
||||||
updateOrientationMarkers(element, viewport);
|
updateOrientationMarkers(element, viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
flipH = function() {
|
flipH = function() {
|
||||||
var element = getActiveViewportElement();
|
const element = getActiveViewportElement();
|
||||||
var viewport = cornerstone.getViewport(element);
|
let viewport = cornerstone.getViewport(element);
|
||||||
viewport.hflip = (viewport.hflip === false);
|
viewport.hflip = (viewport.hflip === false);
|
||||||
cornerstone.setViewport(element, viewport);
|
cornerstone.setViewport(element, viewport);
|
||||||
updateOrientationMarkers(element, viewport);
|
updateOrientationMarkers(element, viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
resetViewport = function() {
|
||||||
|
const element = getActiveViewportElement();
|
||||||
|
const enabledElement = cornerstone.getEnabledElement(element);
|
||||||
|
if (enabledElement.fitToWindow === false) {
|
||||||
|
const imageId = enabledElement.image.imageId;
|
||||||
|
const instance = cornerstoneTools.metaData.get('instance', imageId);
|
||||||
|
|
||||||
|
enabledElement.viewport = cornerstone.getDefaultViewport(enabledElement.canvas, enabledElement.image);
|
||||||
|
|
||||||
|
const instanceClassDefaultViewport = getInstanceClassDefaultViewport(instance, enabledElement, imageId);
|
||||||
|
cornerstone.setViewport(element, instanceClassDefaultViewport);
|
||||||
|
} else {
|
||||||
|
cornerstone.reset(element);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
clearTools = function() {
|
||||||
|
const element = getActiveViewportElement();
|
||||||
|
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
|
||||||
|
toolStateManager.clear(element);
|
||||||
|
cornerstone.updateImage(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCinePlay = function() {
|
||||||
|
const element = getActiveViewportElement();
|
||||||
|
var viewportIndex = Session.get('activeViewport');
|
||||||
|
|
||||||
|
var isPlaying = OHIF.viewer.isPlaying[viewportIndex] || false;
|
||||||
|
if (isPlaying) {
|
||||||
|
cornerstoneTools.stopClip(element);
|
||||||
|
} else {
|
||||||
|
cornerstoneTools.playClip(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
OHIF.viewer.isPlaying[viewportIndex] = !OHIF.viewer.isPlaying[viewportIndex];
|
||||||
|
Session.set('UpdateCINE', Random.id());
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCineDialog = function() {
|
||||||
|
var cineDialog = document.getElementById('cineDialog');
|
||||||
|
toggleDialog(cineDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
isPlaying = function() {
|
||||||
|
Session.get('UpdateCINE');
|
||||||
|
var activeViewport = Session.get('activeViewport');
|
||||||
|
|
||||||
|
// TODO=Check best way to make sure this is always defined
|
||||||
|
// Right now it is initialized in enableHotkeys AND in
|
||||||
|
// imageViewer onCreated, but this appears to break some things
|
||||||
|
if (!OHIF.viewer.isPlaying) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!OHIF.viewer.isPlaying[activeViewport];
|
||||||
|
};
|
||||||
@ -90,6 +90,9 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('client/components/viewer/imageControls/imageControls.js', 'client');
|
api.addFiles('client/components/viewer/imageControls/imageControls.js', 'client');
|
||||||
api.addFiles('client/components/viewer/imageControls/imageControls.styl', 'client');
|
api.addFiles('client/components/viewer/imageControls/imageControls.styl', 'client');
|
||||||
|
|
||||||
|
api.addFiles('client/components/viewer/layoutButton/layoutButton.html', 'client');
|
||||||
|
api.addFiles('client/components/viewer/layoutButton/layoutButton.js', 'client');
|
||||||
|
|
||||||
api.addFiles('client/components/viewer/layoutChooser/layoutChooser.html', 'client');
|
api.addFiles('client/components/viewer/layoutChooser/layoutChooser.html', 'client');
|
||||||
api.addFiles('client/components/viewer/layoutChooser/layoutChooser.js', 'client');
|
api.addFiles('client/components/viewer/layoutChooser/layoutChooser.js', 'client');
|
||||||
api.addFiles('client/components/viewer/layoutChooser/layoutChooser.styl', 'client');
|
api.addFiles('client/components/viewer/layoutChooser/layoutChooser.styl', 'client');
|
||||||
@ -106,16 +109,9 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.js', 'client');
|
api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.js', 'client');
|
||||||
api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.styl', 'client');
|
api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.styl', 'client');
|
||||||
|
|
||||||
api.addFiles('client/components/viewer/simpleToolbarButton/simpleToolbarButton.html', 'client');
|
|
||||||
api.addFiles('client/components/viewer/simpleToolbarButton/simpleToolbarButton.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/viewer/playClipButton/playClipButton.html', 'client');
|
api.addFiles('client/components/viewer/playClipButton/playClipButton.html', 'client');
|
||||||
api.addFiles('client/components/viewer/playClipButton/playClipButton.js', 'client');
|
api.addFiles('client/components/viewer/playClipButton/playClipButton.js', 'client');
|
||||||
|
|
||||||
api.addFiles('client/components/viewer/toolbar/toolbar.html', 'client');
|
|
||||||
api.addFiles('client/components/viewer/toolbar/toolbar.js', 'client');
|
|
||||||
api.addFiles('client/components/viewer/toolbar/toolbar.styl', 'client');
|
|
||||||
|
|
||||||
// Library functions
|
// Library functions
|
||||||
api.addFiles('lib/layoutManager.js', 'client');
|
api.addFiles('lib/layoutManager.js', 'client');
|
||||||
api.addFiles('lib/createStacks.js', 'client');
|
api.addFiles('lib/createStacks.js', 'client');
|
||||||
@ -204,6 +200,14 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('lib/helpers/isTouchDevice.js', 'client');
|
api.addFiles('lib/helpers/isTouchDevice.js', 'client');
|
||||||
api.export('isTouchDevice', 'client');
|
api.export('isTouchDevice', 'client');
|
||||||
|
|
||||||
|
// TODO: Clean this up later, no real need to export these
|
||||||
|
// Need to move functionList into viewerbase
|
||||||
|
api.export('toggleCineDialog', 'client');
|
||||||
|
api.export('toggleCinePlay', 'client');
|
||||||
|
api.export('clearTools', 'client');
|
||||||
|
api.export('resetViewport', 'client');
|
||||||
|
api.export('invert', 'client');
|
||||||
|
|
||||||
api.addFiles('server/methods/importStudies.js', 'server');
|
api.addFiles('server/methods/importStudies.js', 'server');
|
||||||
|
|
||||||
api.export('importStudies', 'server');
|
api.export('importStudies', 'server');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user