Fixed OHIF Viewer layout / CINE / Hanging Protocol buttons (OHIF-49)

This commit is contained in:
Erik Ziegler committed 2016-07-23 15:56:36 +02:00
1 parent 59c851fa57
commit 8b364ce9d0
37 files changed
+496 -709

No files matched your search

@@ -1,41 +1,47 @@
<template name="cineDialog">
<div id="cineDialog">
<h5>Cine Controls</h5>
<div id="cineButtons">
<a id="cineFirstButton" title="Skip to first image" class="cineButton" data-toggle="tooltip">
<i class="fa fa-lg fa-fast-backward"></i>
<div id="cineDialog" class="noselect">
<h5>CINE Controls</h5>
<div class="btn-group">
<a id="cineFirstButton" title="Skip to first image" class="btn" data-toggle="tooltip">
<i class="fa fa-fast-backward"></i>
</a>
<a id="cineBackButton" title="Previous image" class="cineButton" data-toggle="tooltip">
<i class="fa fa-lg fa-step-backward"></i>
<a id="cineBackButton" title="Previous image" class="btn" data-toggle="tooltip">
<i class="fa fa-step-backward"></i>
</a>
<a id="cineSlowPlaybackButton" title="Slow playback" class="cineButton" data-toggle="tooltip">
<i class="fa fa-lg fa-backward"></i>
<a id="cineSlowPlaybackButton" title="Slow playback" class="btn" data-toggle="tooltip">
<i class="fa fa-backward"></i>
</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}}
<i class="fa fa-lg fa-pause"></i>
<i class="fa fa-fw fa-stop"></i>
{{else}}
<i class="fa fa-lg fa-play"></i>
<i class="fa fa-fw fa-play"></i>
{{/if}}
</a>
<a id="cineFastForwardButton" title="Increase playback speed" class="cineButton" data-toggle="tooltip">
<i class="fa fa-lg fa-forward"></i>
<a id="cineFastForwardButton" title="Increase playback speed" class="btn" data-toggle="tooltip">
<i class="fa fa-forward"></i>
</a>
<a id="cineNextButton" title="Next image" class="cineButton" data-toggle="tooltip">
<i class="fa fa-lg fa-step-forward"></i>
<a id="cineNextButton" title="Next image" class="btn" data-toggle="tooltip">
<i class="fa fa-step-forward"></i>
</a>
<a id="cineLastButton" title="Skip to last image" class="cineButton" data-toggle="tooltip">
<i class="fa fa-lg fa-fast-forward"></i>
<a id="cineLastButton" title="Skip to last image" class="btn" data-toggle="tooltip">
<i class="fa fa-fast-forward"></i>
</a>
</div>
<div id="cineOptions">
<div id="loopSection">
<label>Loop?</label>
<label for="cineLoopCheckbox">Loop?</label>
<input type="checkbox" checked id="cineLoopCheckbox" />
</div>
<div id="fpsSection">
<label>Cine Speed: <span id="fps">{{framerate}}</span></label>
<input type="range" id="cineSlider" min="1" max="90" value="{{framerate}}"/>
<label for="cineSlider">
Cine Speed: <span id="fps">{{framerate}}</span>
</label>
<input type="range"
id="cineSlider"
min="1"
max="90"
value="{{framerate}}"/>
</div>
</div>
</div>
@@ -1,16 +1,5 @@
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) {
OHIF.viewer.cine.framesPerSecond = rate;
@@ -74,6 +63,7 @@ Template.cineDialog.events({
});
Template.cineDialog.onRendered(function() {
var dialog = $('#cineDialog');
const instance = Template.instance();
const dialog = instance.$('#cineDialog');
dialog.draggable();
});
@@ -1,3 +1,7 @@
@import "{design}/app.styl"
$borderColor = rgba(77, 99, 110, 0.81)
#cineDialog
display: none
z-index: 1000
@@ -9,32 +13,29 @@
overflow: hidden
padding: 10px
width: 250px
width: 300px
height: 175px
border: 1px black solid
border-radius: 3px
background: white
color: black
opacity: 0.95
border-radius: 8px
border: 1px solid $borderColor;
background: $uiGrayDarkest
color: $textSecondaryColor
h5, label
font-weight: 100
box-sizing: border-box
-webkit-user-select: none
-moz-user-select: none
-o-user-select: none
-ms-user-select: none
-khtml-user-select: none
user-select: none
#cineButtons
padding-bottom: 10px
overflow: auto
.btn
background: $uiGrayDarkest
color: $textSecondaryColor
.cineButton
cursor: pointer
margin: 0 6px
text-decoration: none
&:hover
color: $hoverColor
&:active, &.active
color: $activeColor
#cineOptions
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">
<div class="layoutChooser pull-left dropdown-menu" role="menu">
<div id="layoutChooser" class="layoutChooser pull-left dropdown-menu" role="menu">
<table>
<tr>
<td></td>
@@ -6,39 +6,41 @@
* @param currentCell
*/
function highlightCells(currentCell) {
var cells = $('.layoutChooser table td');
const cells = $('.layoutChooser table td');
cells.removeClass('hover');
currentCell = $(currentCell);
var table = currentCell.parents('.layoutChooser table').get(0);
var rowIndex = currentCell.closest('tr').index();
var columnIndex = currentCell.index();
const table = currentCell.parents('.layoutChooser table').get(0);
const rowIndex = currentCell.closest('tr').index();
const columnIndex = currentCell.index();
// Loop through the table row by row
// and cell by cell to apply the highlighting
for (var i = 0; i < table.rows.length; i++) {
row = table.rows[i];
const row = table.rows[i];
if (i <= rowIndex) {
for (var j = 0; j < row.cells.length; j++) {
for (var j = 0; j < row.cells.length; j++) {
if (j <= columnIndex) {
cell = row.cells[j];
const cell = row.cells[j];
cell.classList.add('hover');
}
}
}
}
}
}
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);
},
'click .layoutChooser table td': function(evt) {
var currentCell = $(evt.currentTarget);
var rowIndex = currentCell.closest('tr').index();
var columnIndex = currentCell.index();
'click .layoutChooser table td'(evt) {
const currentCell = $(evt.currentTarget);
const rowIndex = currentCell.closest('tr').index();
const columnIndex = currentCell.index();
// Add 1 because the indices start from zero
var layoutProps = {
const layoutProps = {
rows: rowIndex + 1,
columns: columnIndex + 1
};
@@ -46,5 +48,8 @@ Template.layoutChooser.events({
layoutManager.layoutTemplateName = 'gridLayout';
layoutManager.layoutProps = layoutProps;
layoutManager.updateViewports();
const $dropdown = $('.layoutChooser');
toggleDialog($dropdown);
}
});
});
@@ -1,19 +1,28 @@
@import "{design}/app.styl"
$borderColor = rgba(77, 99, 110, 0.81)
.layoutChooser
width: 92px
height: 92px
min-width: 92px // to override bootstrap's dropdown-menu class
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
margin: 0 auto
td
cursor: pointer
border: 2px solid $uiBorderColorDark
border: 1px solid $uiBorderColorDark
width: 20px
height: 20px
transition(background-color 0.1s ease)
@@ -14,7 +14,7 @@
p, h4
text-align: center
color: $textColorActive
padding: 4px 0px
padding: 4px 0
p
font-size: 11pt
@@ -1,24 +1,20 @@
<template name="playClipButton">
<button id="playClip"
type="button"
class="imageViewerCommand btn btn-sm {{ #if isPlaying }}active{{/if}}"
data-container="body"
data-toggle="tooltip"
data-placement="bottom"
title="Play/Stop Clip">
<div id="{{this.id}}"
class="toolbarSectionButton rp-x-1 {{this.classes}} {{activeClass}} {{ #if isPlaying }}active{{/if}}"
title="{{this.title}}">
<div class="svgContainer">
{{ #if isPlaying }}
<span class="fa fa-stop"></span>
<i class="fa fa-stop fa-fw"></i>
{{ else }}
<span class="fa fa-play"></span>
<i class="fa fa-play fa-fw"></i>
{{ /if }}
</button>
<button id="toggleCineDialog"
type="button"
class="imageViewerCommand btn btn-sm"
data-container="body"
data-toggle="tooltip"
data-placement="bottom"
title="Toggle CINE Dialog">
<span class="fa fa-youtube-play"></span>
</button>
</div>
<div class="buttonLabel">
{{ #if isPlaying }}
Stop
{{ else }}
Play
{{/if}}
</div>
</div>
</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({
isPlaying: function() {
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,7 +1,12 @@
<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">
{{ #if this.svgLink }}
{{ #if this.svgLink }}
<svg>
<use xlink:href={{this.svgLink}}></use>
</svg>
@@ -13,4 +18,5 @@
{{this.title}}
</div>
</div>
{{ /if }}
</template>
@@ -30,7 +30,7 @@ Template.toolbarSectionButton.events({
},
'click .imageViewerCommand'(event, instance) {
const command = event.currentTarget.id;
if (!OHIF.viewer.functionList.hasOwnProperty(command)) {
if (!OHIF.viewer.functionList || !OHIF.viewer.functionList.hasOwnProperty(command)) {
return;
}
@@ -4,6 +4,7 @@
{{>toolbarSectionButton toolbarButton}}
{{/each}}
{{ #if extraToolbarButtons}}
<div id="moreTools" class="js-open-more-tools toolbarSectionButton rp-x-1 rm-l-3">
<div class="svgContainer">
<svg>
@@ -24,5 +25,6 @@
{{/each}}
</div>
</div>
{{ /if }}
</div>
</template>
@@ -1,10 +1,26 @@
Template.viewerMain.onRendered(function() {
var instance = this;
var studies = instance.data.studies;
Template.viewerMain.onCreated(() => {
// Attach the Window resize listener
$(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);
ProtocolEngine = new HP.ProtocolEngine(window.layoutManager, studies);
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();
});