Most JS files, all helpers and simple reconciliations
This commit is contained in:
1 parent
21400c5836
commit
9e69c43dda
58 files changed
+776
-1025
No files matched your search
+11
-1
@@ -1,6 +1,10 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { Session } from 'meteor/session';
|
||||
// OHIF Modules
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
// Local Modules
|
||||
import { getImageId } from '../../../lib/getImageId.js';
|
||||
|
||||
Template.imageThumbnail.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
@@ -26,6 +30,10 @@ Template.imageThumbnail.onRendered(() => {
|
||||
const element = $element.get(0);
|
||||
|
||||
instance.refreshImage = () => {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable cornerstone for thumbnail element and remove its canvas
|
||||
cornerstone.disable(element);
|
||||
|
||||
@@ -75,7 +83,9 @@ Template.imageThumbnail.onDestroyed(() => {
|
||||
const $element = $parent.find('.imageThumbnailCanvas');
|
||||
const element = $element.get(0);
|
||||
|
||||
cornerstone.disable(element);
|
||||
if (element) {
|
||||
cornerstone.disable(element);
|
||||
}
|
||||
});
|
||||
|
||||
Template.imageThumbnail.helpers({
|
||||
|
||||
+10
-203
@@ -1,202 +1,9 @@
|
||||
const cloneElement = (element, targetId) => {
|
||||
// Clone the DOM element
|
||||
const clone = element.cloneNode(true);
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { Session } from 'meteor/session';
|
||||
|
||||
// Find any canvas children to clone
|
||||
const clonedCanvases = $(clone).find('canvas');
|
||||
clonedCanvases.each((canvasIndex, clonedCanvas) => {
|
||||
// Draw from the original canvas to the cloned canvas
|
||||
const context = clonedCanvas.getContext('2d');
|
||||
const thumbnailCanvas = $(element).find('canvas').get(canvasIndex);
|
||||
context.drawImage(thumbnailCanvas, 0, 0);
|
||||
});
|
||||
|
||||
// Update the clone with the targetId
|
||||
clone.id = targetId;
|
||||
clone.style.visibility = 'hidden';
|
||||
return clone;
|
||||
};
|
||||
|
||||
const thumbnailDragStartHandler = (event, data) => {
|
||||
// Prevent any scrolling behaviour normally caused by the original event
|
||||
event.originalEvent.preventDefault();
|
||||
|
||||
// Identify the current study and series index from the thumbnail's DOM position
|
||||
const targetThumbnail = event.currentTarget;
|
||||
const $imageThumbnail = $(targetThumbnail);
|
||||
|
||||
// Clone the image thumbnail
|
||||
const targetId = 'DragClone';
|
||||
const clone = cloneElement(targetThumbnail, targetId);
|
||||
const $clone = $(clone);
|
||||
$clone.addClass('imageThumbnailClone');
|
||||
|
||||
// Set pointerEvents to pass through the clone DOM element
|
||||
// This is necessary in order to identify what is below it
|
||||
// when using document.elementFromPoint
|
||||
clone.style.pointerEvents = 'none';
|
||||
|
||||
// Append the clone to the body
|
||||
document.body.appendChild(clone);
|
||||
|
||||
// Set the cursor x and y positions from the current touch/mouse coordinates
|
||||
let cursorX, cursorY;
|
||||
// Handle touchStart cases
|
||||
if (event.type === 'touchstart') {
|
||||
cursorX = event.originalEvent.touches[0].pageX;
|
||||
cursorY = event.originalEvent.touches[0].pageY;
|
||||
} else {
|
||||
cursorX = event.pageX;
|
||||
cursorY = event.pageY;
|
||||
|
||||
// Also hook up event handlers for mouse events
|
||||
const handlers = {};
|
||||
handlers.mousemove = event => thumbnailDragHandler(event);
|
||||
handlers.mouseup = event => thumbnailDragEndHandler(event, data, handlers);
|
||||
$(document).on('mousemove', handlers.mousemove);
|
||||
$(document).on('mouseup', handlers.mouseup);
|
||||
}
|
||||
|
||||
// This block gets the current offset of the touch/mouse
|
||||
// relative to the window
|
||||
//
|
||||
// i.e. Where did the user grab it from?
|
||||
const offset = $imageThumbnail.offset();
|
||||
const left = offset.left;
|
||||
const top = offset.top;
|
||||
|
||||
// This difference is saved for later so the element movement looks normal
|
||||
const diff = {
|
||||
x: cursorX - left,
|
||||
y: cursorY - top
|
||||
};
|
||||
$clone.data('diff', diff);
|
||||
|
||||
// This sets the default style properties of the cloned element so it is
|
||||
// ready to be dragged around the page
|
||||
$clone.css({
|
||||
left: cursorX - diff.x,
|
||||
position: 'fixed',
|
||||
top: cursorY - diff.y,
|
||||
visibility: 'hidden',
|
||||
'z-index': 100000
|
||||
});
|
||||
};
|
||||
|
||||
const thumbnailDragHandler = event => {
|
||||
// Get the touch/mouse coordinates from the event
|
||||
let cursorX, cursorY;
|
||||
if (event.type === 'touchmove') {
|
||||
cursorX = event.originalEvent.changedTouches[0].pageX;
|
||||
cursorY = event.originalEvent.changedTouches[0].pageY;
|
||||
} else {
|
||||
cursorX = event.pageX;
|
||||
cursorY = event.pageY;
|
||||
}
|
||||
|
||||
// Find the clone element and update it's position on the page
|
||||
const $clone = $('#DragClone');
|
||||
const diff = $clone.data('diff');
|
||||
$clone.css({
|
||||
left: cursorX - diff.x,
|
||||
position: 'fixed',
|
||||
top: cursorY - diff.y,
|
||||
visibility: 'visible',
|
||||
'z-index': 100000
|
||||
});
|
||||
|
||||
// Identify the element below the current cursor position
|
||||
const elemBelow = document.elementFromPoint(cursorX, cursorY);
|
||||
|
||||
// If none exists, stop here
|
||||
if (!elemBelow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove any current faded effects on viewports
|
||||
$('.imageViewerViewport canvas').removeClass('faded');
|
||||
|
||||
// Figure out what to do depending on what we're dragging over
|
||||
const $viewportsDraggedOver = $(elemBelow).parents('.imageViewerViewport');
|
||||
if ($viewportsDraggedOver.length) {
|
||||
// If we're dragging over a non-empty viewport, fade it and change the cursor style
|
||||
$viewportsDraggedOver.find('canvas').not('.magnifyTool').addClass('faded');
|
||||
document.body.style.cursor = 'copy';
|
||||
} else if (elemBelow.classList.contains('imageViewerViewport') && elemBelow.classList.contains('empty')) {
|
||||
// If we're dragging over an empty viewport, just change the cursor style
|
||||
document.body.style.cursor = 'copy';
|
||||
} else {
|
||||
// Otherwise, keep the cursor as no-drop style
|
||||
document.body.style.cursor = 'no-drop';
|
||||
}
|
||||
};
|
||||
|
||||
const thumbnailDragEndHandler = (event, data, handlers) => {
|
||||
// Remove the mouse event listeners
|
||||
if (handlers) {
|
||||
$(document).off('mousemove', handlers.mousemove);
|
||||
$(document).off('mouseup', handlers.mouseup);
|
||||
}
|
||||
|
||||
// Reset the cursor style to the default
|
||||
document.body.style.cursor = 'auto';
|
||||
|
||||
// Get the cloned element
|
||||
const $clone = $('#DragClone');
|
||||
|
||||
// If it doesn't exist, stop here
|
||||
if (!$clone.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const top = $clone.offset().top;
|
||||
const left = $clone.offset().left;
|
||||
const diff = $clone.data('diff');
|
||||
|
||||
// Identify the element below the cloned element position
|
||||
const elemBelow = document.elementFromPoint(left + diff.x, top + diff.y);
|
||||
|
||||
// Remove all cloned elements from the page
|
||||
$('.imageThumbnailClone').remove();
|
||||
|
||||
// Remove any current faded effects on viewports
|
||||
$('.imageViewerViewport canvas').removeClass('faded');
|
||||
|
||||
// If none exists, stop here
|
||||
if (!elemBelow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove any fade effects on the element below
|
||||
elemBelow.classList.remove('faded');
|
||||
|
||||
let element;
|
||||
const $viewportsDraggedOver = $(elemBelow).closest('.imageViewerViewport');
|
||||
if ($viewportsDraggedOver.length) {
|
||||
// If we're dragging over a non-empty viewport, retrieve it
|
||||
element = $viewportsDraggedOver.get(0);
|
||||
} else if (elemBelow.classList.contains('imageViewerViewport') &&
|
||||
elemBelow.classList.contains('empty')) {
|
||||
// If we're dragging over an empty viewport, retrieve that instead
|
||||
element = elemBelow;
|
||||
} else {
|
||||
// Otherwise, stop here
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is no stored drag and drop data, stop here
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the dropped viewport index
|
||||
const viewportIndex = $('.imageViewerViewport').index(element);
|
||||
|
||||
// Rerender the viewport using the dragged thumbnail data
|
||||
window.layoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, data);
|
||||
|
||||
return false;
|
||||
};
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { thumbnailDragHandlers } from '../../../lib/thumbnailDragHandlers';
|
||||
|
||||
Template.thumbnailEntry.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
@@ -209,16 +16,16 @@ Template.thumbnailEntry.events({
|
||||
// Event handlers for drag and drop
|
||||
'touchstart .thumbnailEntry, mousedown .thumbnailEntry'(event, instance) {
|
||||
const data = instance.data.thumbnail.stack;
|
||||
instance.isDragAndDrop && thumbnailDragStartHandler(event, data);
|
||||
instance.isDragAndDrop && thumbnailDragHandlers.thumbnailDragStartHandler(event, data);
|
||||
},
|
||||
|
||||
'touchmove .thumbnailEntry'(event, instance) {
|
||||
instance.isDragAndDrop && thumbnailDragHandler(event);
|
||||
instance.isDragAndDrop && thumbnailDragHandlers.thumbnailDragHandler(event);
|
||||
},
|
||||
|
||||
'touchend .thumbnailEntry'(event, instance) {
|
||||
const data = instance.data.thumbnail.stack;
|
||||
instance.isDragAndDrop && thumbnailDragEndHandler(event, data);
|
||||
instance.isDragAndDrop && thumbnailDragHandlers.thumbnailDragEndHandler(event, data);
|
||||
},
|
||||
|
||||
// Event handlers for click (quick switch)
|
||||
@@ -228,7 +35,7 @@ Template.thumbnailEntry.events({
|
||||
const data = instance.data.thumbnail.stack;
|
||||
|
||||
// Rerender the viewport using the clicked thumbnail data
|
||||
window.layoutManager.rerenderViewportWithNewDisplaySet(instance.data.viewportIndex, data);
|
||||
OHIF.viewerbase.layoutManager.rerenderViewportWithNewDisplaySet(instance.data.viewportIndex, data);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -241,7 +48,7 @@ Template.thumbnailEntry.events({
|
||||
const data = instance.data.thumbnail.stack;
|
||||
|
||||
// Rerender the viewport using the clicked thumbnail data
|
||||
window.layoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, data);
|
||||
OHIF.viewerbase.layoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
-115
@@ -1,118 +1,3 @@
|
||||
// ------ Tool configuration functions ----- //
|
||||
getAnnotationTextCallback = function(doneChangingTextCallback) {
|
||||
// This handles the text entry for the annotation tool
|
||||
function keyPressHandler(e) {
|
||||
// If Enter or Esc are pressed, close the dialog
|
||||
if (e.which === 13 || e.which === 27) {
|
||||
closeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
function closeHandler() {
|
||||
dialog.get(0).close();
|
||||
doneChangingTextCallback(getTextInput.val());
|
||||
// Reset the text value
|
||||
getTextInput.val('');
|
||||
|
||||
// Reset the focus to the active viewport element
|
||||
// This makes the mobile Safari keyboard close
|
||||
const element = getActiveViewportElement();
|
||||
$(element).focus();
|
||||
}
|
||||
|
||||
const dialog = $('#annotationDialog');
|
||||
if (dialog.get(0).open === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
const getTextInput = $('.annotationTextInput');
|
||||
|
||||
// Focus on the text input to open the Safari keyboard
|
||||
getTextInput.focus();
|
||||
|
||||
dialog.get(0).showModal();
|
||||
|
||||
const confirm = dialog.find('.annotationDialogConfirm');
|
||||
confirm.off('click');
|
||||
confirm.on('click', () => {
|
||||
closeHandler();
|
||||
});
|
||||
|
||||
// Use keydown since keypress doesn't handle ESC in Chrome
|
||||
dialog.off('keydown');
|
||||
dialog.on('keydown', keyPressHandler);
|
||||
};
|
||||
|
||||
changeAnnotationTextCallback = function(data, eventData, doneChangingTextCallback) {
|
||||
const dialog = $('#relabelAnnotationDialog');
|
||||
if (dialog.get(0).open === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTouchDevice()) {
|
||||
// Center the dialog on screen on touch devices
|
||||
dialog.css({
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
margin: 'auto'
|
||||
});
|
||||
} else {
|
||||
// Place the dialog above the tool that is being relabelled
|
||||
dialog.css({
|
||||
top: eventData.currentPoints.page.y - dialog.outerHeight() - 20,
|
||||
left: eventData.currentPoints.page.x - dialog.outerWidth() / 2
|
||||
});
|
||||
}
|
||||
|
||||
const getTextInput = dialog.find('.annotationTextInput');
|
||||
const confirm = dialog.find('.relabelConfirm');
|
||||
const remove = dialog.find('.relabelRemove');
|
||||
|
||||
getTextInput.val(data.text);
|
||||
|
||||
// Focus on the text input to open the Safari keyboard
|
||||
getTextInput.focus();
|
||||
|
||||
dialog.get(0).showModal();
|
||||
|
||||
confirm.off('click');
|
||||
confirm.on('click', function() {
|
||||
dialog.get(0).close();
|
||||
doneChangingTextCallback(data, getTextInput.val());
|
||||
});
|
||||
|
||||
// If the remove button is clicked, delete this marker
|
||||
remove.off('click');
|
||||
remove.on('click', function() {
|
||||
dialog.get(0).close();
|
||||
doneChangingTextCallback(data, undefined, true);
|
||||
});
|
||||
|
||||
dialog.off('keydown');
|
||||
dialog.on('keydown', keyPressHandler);
|
||||
|
||||
function keyPressHandler(e) {
|
||||
// If Enter is pressed, close the dialog
|
||||
if (e.which === 13) {
|
||||
closeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
function closeHandler() {
|
||||
dialog.get(0).close();
|
||||
doneChangingTextCallback(data, getTextInput.val());
|
||||
// Reset the text value
|
||||
getTextInput.val('');
|
||||
|
||||
// Reset the focus to the active viewport element
|
||||
// This makes the mobile Safari keyboard close
|
||||
const element = getActiveViewportElement();
|
||||
$(element).focus();
|
||||
}
|
||||
};
|
||||
|
||||
Template.annotationDialogs.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
const dialogIds = ['annotationDialog', 'relabelAnnotationDialog'];
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Session } from 'meteor/session';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { viewportUtils } from '../../../lib/viewportUtils';
|
||||
import { switchToImageRelative } from '../../../lib/switchToImageRelative';
|
||||
import { switchToImageByIndex } from '../../../lib/switchToImageByIndex';
|
||||
|
||||
Template.cineDialog.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
@@ -34,18 +37,15 @@ Template.cineDialog.onCreated(() => {
|
||||
OHIF.viewer.cine.framesPerSecond = rate;
|
||||
|
||||
// Update playClip toolData for this imageId
|
||||
const element = getActiveViewportElement();
|
||||
const element = viewportUtils.getActiveViewportElement();
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const playClipToolData = cornerstoneTools.getToolState(element, 'playClip');
|
||||
playClipToolData.data[0].framesPerSecond = OHIF.viewer.cine.framesPerSecond;
|
||||
|
||||
// If the movie is playing, stop/start to update the framerate
|
||||
if (isPlaying()) {
|
||||
if (viewportUtils.isPlaying()) {
|
||||
cornerstoneTools.stopClip(element);
|
||||
cornerstoneTools.playClip(element);
|
||||
cornerstoneTools.playClip(element, OHIF.viewer.cine.framesPerSecond);
|
||||
}
|
||||
|
||||
Session.set('UpdateCINE', Random.id());
|
||||
@@ -55,7 +55,7 @@ Template.cineDialog.onCreated(() => {
|
||||
instance.api = {
|
||||
displaySetPrevious: () => OHIF.viewer.moveDisplaySets(false),
|
||||
displaySetNext: () => OHIF.viewer.moveDisplaySets(true),
|
||||
cineToggle: () => toggleCinePlay(),
|
||||
cineToggle: () => viewportUtils.toggleCinePlay(),
|
||||
cineFirst: () => switchToImageByIndex(0),
|
||||
cineLast: () => switchToImageByIndex(-1),
|
||||
cinePrevious: () => switchToImageRelative(-1),
|
||||
@@ -80,13 +80,19 @@ Template.cineDialog.onCreated(() => {
|
||||
|
||||
Tracker.afterFlush(() => {
|
||||
// Get the active viewportElement
|
||||
const element = getActiveViewportElement();
|
||||
const element = viewportUtils.getActiveViewportElement();
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if playClip tool has been initialized...
|
||||
const playClipData = cornerstoneTools.getToolState(element, 'playClip');
|
||||
if (!playClipData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the cornerstone playClip tool data
|
||||
const toolData = cornerstoneTools.getToolState(element, 'playClip').data[0];
|
||||
const toolData = playClipData.data[0];
|
||||
|
||||
// Get the cine object
|
||||
const cine = OHIF.viewer.cine;
|
||||
@@ -99,7 +105,10 @@ Template.cineDialog.onCreated(() => {
|
||||
cine.loop = _.isUndefined(cine.loop) ? true : cine.loop;
|
||||
|
||||
// Set the updated data on the form inputs
|
||||
instance.$('form:first').data('component').value(cine);
|
||||
const elementComponent = instance.$('form:first').data('component');
|
||||
if (elementComponent) {
|
||||
elementComponent.value(cine);
|
||||
}
|
||||
|
||||
// Update the session to refresh the framerate text
|
||||
Session.set('UpdateCINE', Random.id());
|
||||
@@ -204,11 +213,9 @@ Template.cineDialog.onCreated(() => {
|
||||
});
|
||||
|
||||
Template.cineDialog.onRendered(() => {
|
||||
|
||||
const instance = Template.instance();
|
||||
|
||||
let dialog = instance.$('#cineDialog'),
|
||||
singleRowLayout = OHIF.uiSettings.displayEchoUltrasoundWorkflow;
|
||||
const dialog = instance.$('#cineDialog');
|
||||
const singleRowLayout = OHIF.uiSettings.displayEchoUltrasoundWorkflow;
|
||||
|
||||
// set dialog in optimal position and make sure it continues in a optimal position...
|
||||
// ... when the window has been resized
|
||||
@@ -222,7 +229,10 @@ Template.cineDialog.onRendered(() => {
|
||||
instance.setResizeHandler(instance.setOptimalPosition);
|
||||
|
||||
// Make the CINE dialog bounded and draggable
|
||||
dialog.bounded().draggable({ defaultElementCursor: 'move' });
|
||||
dialog.draggable({ defaultElementCursor: 'move' });
|
||||
|
||||
// Polyfill for older browsers
|
||||
dialogPolyfill.registerDialog(dialog.get(0));
|
||||
|
||||
// Prevent dialog from being dragged when user clicks any button
|
||||
dialog.find('.cine-navigation, .cine-controls, .cine-options').on('mousedown touchstart', function (e) {
|
||||
@@ -239,7 +249,7 @@ Template.cineDialog.onDestroyed(() => {
|
||||
|
||||
Template.cineDialog.events({
|
||||
'change [data-key=loop] input'(event, instance) {
|
||||
const element = getActiveViewportElement();
|
||||
const element = viewportUtils.getActiveViewportElement();
|
||||
const playClipToolData = cornerstoneTools.getToolState(element, 'playClip');
|
||||
playClipToolData.data[0].loop = $(event.currentTarget).is(':checked');
|
||||
OHIF.viewer.cine.loop = playClipToolData.data[0].loop;
|
||||
@@ -254,7 +264,7 @@ Template.cineDialog.events({
|
||||
|
||||
Template.cineDialog.helpers({
|
||||
isPlaying() {
|
||||
return isPlaying();
|
||||
return viewportUtils.isPlaying();
|
||||
},
|
||||
|
||||
framerate() {
|
||||
@@ -264,11 +274,11 @@ Template.cineDialog.helpers({
|
||||
|
||||
displaySetDisabled(isNext) {
|
||||
Session.get('LayoutManagerUpdated');
|
||||
return !OHIF.viewer.canMoveDisplaySets(isNext) ? 'disabled' : '';
|
||||
return !OHIF.viewerbase.layoutManager.canMoveDisplaySets(isNext) ? 'disabled' : '';
|
||||
},
|
||||
|
||||
buttonDisabled() {
|
||||
return hasMultipleFrames();
|
||||
return viewportUtils.hasMultipleFrames();
|
||||
},
|
||||
|
||||
getClassNames(baseCls) {
|
||||
|
||||
+15
-63
@@ -1,69 +1,26 @@
|
||||
function closeHandler() {
|
||||
// Hide the lesion dialog
|
||||
$('#confirmDeleteDialog').css('display', 'none');
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
// Remove the backdrop
|
||||
$('.removableBackdrop').remove();
|
||||
|
||||
// Remove the callback from the template data
|
||||
delete Template.confirmDeleteDialog.doneCallback;
|
||||
|
||||
// Restore the focus to the active viewport
|
||||
setFocusToActiveViewport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the confirmation dialog template and the removable backdrop element
|
||||
*
|
||||
* @param doneCallback A callback
|
||||
* @param options
|
||||
*/
|
||||
showConfirmDialog = function(doneCallback, options) {
|
||||
// Show the backdrop
|
||||
options = options || {};
|
||||
UI.renderWithData(Template.removableBackdrop, options, document.body);
|
||||
|
||||
var confirmDeleteDialog = $('#confirmDeleteDialog');
|
||||
confirmDeleteDialog.remove();
|
||||
|
||||
var viewer = document.getElementById('viewer');
|
||||
UI.renderWithData(Template.confirmDeleteDialog, options, viewer);
|
||||
|
||||
// Make sure the context menu is closed when the user clicks away
|
||||
$('.removableBackdrop').one('mousedown touchstart', function() {
|
||||
closeHandler();
|
||||
});
|
||||
|
||||
confirmDeleteDialog = $('#confirmDeleteDialog');
|
||||
confirmDeleteDialog.css('display', 'block');
|
||||
confirmDeleteDialog.focus();
|
||||
|
||||
if (doneCallback && typeof doneCallback === 'function') {
|
||||
Template.confirmDeleteDialog.doneCallback = doneCallback;
|
||||
}
|
||||
};
|
||||
import { dialogUtils } from '../../../lib/dialogUtils';
|
||||
|
||||
// Global object of key names (TODO: put this somewhere else)
|
||||
keys = {
|
||||
const keys = {
|
||||
ESC: 27,
|
||||
ENTER: 13
|
||||
};
|
||||
|
||||
Template.confirmDeleteDialog.events({
|
||||
'click #cancel, click #close': function() {
|
||||
closeHandler();
|
||||
'click #cancel, click #close'() {
|
||||
// Action canceled, just close dialog without calling callback
|
||||
dialogUtils.closeHandler(false);
|
||||
},
|
||||
'click #confirm': function() {
|
||||
var doneCallback = Template.confirmDeleteDialog.doneCallback;
|
||||
if (doneCallback && typeof doneCallback === 'function') {
|
||||
doneCallback();
|
||||
}
|
||||
|
||||
closeHandler();
|
||||
'click #confirm'() {
|
||||
// Action confirmed, close dialog and calls callback, if exists
|
||||
dialogUtils.closeHandler();
|
||||
},
|
||||
'keydown #confirmDeleteDialog': function(e) {
|
||||
'keydown #confirmDeleteDialog'(e) {
|
||||
// Action canceled, just close dialog without calling callback
|
||||
if (e.which === keys.ESC) {
|
||||
closeHandler();
|
||||
dialogUtils.closeHandler(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -71,15 +28,10 @@ Template.confirmDeleteDialog.events({
|
||||
return;
|
||||
}
|
||||
|
||||
var doneCallback = Template.confirmDeleteDialog.doneCallback;
|
||||
|
||||
// If Enter is pressed, close the dialog
|
||||
// If Enter is pressed
|
||||
if (e.which === keys.ENTER) {
|
||||
if (doneCallback && typeof doneCallback === 'function') {
|
||||
doneCallback();
|
||||
}
|
||||
|
||||
closeHandler();
|
||||
// Action confirmed, close dialog and calls callback, if exists
|
||||
dialogUtils.closeHandler();
|
||||
}
|
||||
}
|
||||
});
|
||||
+2
-2
@@ -15,13 +15,13 @@ Template.displaySetNavigation.events({
|
||||
return;
|
||||
}
|
||||
|
||||
OHIF.viewer.moveDisplaySets(false);
|
||||
OHIF.viewerbase.layoutManager.moveDisplaySets(false);
|
||||
}
|
||||
});
|
||||
|
||||
Template.displaySetNavigation.helpers({
|
||||
disableButton(isNext) {
|
||||
Session.get('LayoutManagerUpdated');
|
||||
return !OHIF.viewer.canMoveDisplaySets(isNext);
|
||||
return !OHIF.viewerbase.layoutManager.canMoveDisplaySets(isNext);
|
||||
}
|
||||
});
|
||||
@@ -1,3 +1,8 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { setActiveViewport } from '../../../lib/setActiveViewport';
|
||||
import { switchToImageByIndex } from '../../../lib/switchToImageByIndex';
|
||||
|
||||
const slideTimeoutTime = 40;
|
||||
let slideTimeout;
|
||||
|
||||
@@ -33,7 +38,7 @@ Template.imageControls.events({
|
||||
OHIF.viewer.hotkeyFunctions.scrollUp();
|
||||
}
|
||||
},
|
||||
'input #imageSlider, change #imageSlider'(event) {
|
||||
'input input[type=range], change input[type=range]'(event) {
|
||||
// Note that we throttle requests to prevent the
|
||||
// user's ultrafast scrolling from firing requests too quickly.
|
||||
clearTimeout(slideTimeout);
|
||||
@@ -41,7 +46,7 @@ Template.imageControls.events({
|
||||
// Using the slider in an inactive viewport
|
||||
// should cause that viewport to become active
|
||||
const slider = $(event.currentTarget);
|
||||
const newActiveElement = slider.parents().eq(2).siblings('.imageViewerViewport').get(0);
|
||||
const newActiveElement = slider.parents('.viewportContainer').find('.imageViewerViewport');
|
||||
setActiveViewport(newActiveElement);
|
||||
|
||||
// Subtract 1 here since the slider goes from 1 to N images
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { viewportUtils } from '../../../lib/viewportUtils';
|
||||
|
||||
Template.layoutButton.events({
|
||||
// TODO: Check why 'click' event won't fire?
|
||||
'mousedown .js-dropdown-toggle'(event) {
|
||||
@@ -12,6 +16,6 @@ Template.layoutButton.events({
|
||||
});
|
||||
|
||||
// Open or close the layout chooser dialog
|
||||
toggleDialog($dropdown);
|
||||
viewportUtils.toggleDialog($dropdown);
|
||||
}
|
||||
});
|
||||
@@ -1,3 +1,9 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
import { viewportUtils } from '../../../lib/viewportUtils';
|
||||
|
||||
Template.layoutChooser.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
@@ -35,12 +41,12 @@ Template.layoutChooser.onRendered(() => {
|
||||
// Refresh layout chooser highlighting based on current viewports state
|
||||
instance.refreshHighlights = () => {
|
||||
// Stop here if layoutManager is not defined yet
|
||||
if (!window.layoutManager) {
|
||||
if (!OHIF.viewerbase.layoutManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the layout rows and columns amount
|
||||
const info = window.layoutManager.layoutProps;
|
||||
const info = OHIF.viewerbase.layoutManager.layoutProps;
|
||||
|
||||
// get the limiter cell
|
||||
const cell = instance.$('tr').eq(info.rows - 1).children().eq(info.columns - 1);
|
||||
@@ -77,11 +83,11 @@ Template.layoutChooser.events({
|
||||
columns: columnIndex + 1
|
||||
};
|
||||
|
||||
window.layoutManager.layoutTemplateName = 'gridLayout';
|
||||
window.layoutManager.layoutProps = layoutProps;
|
||||
window.layoutManager.updateViewports();
|
||||
OHIF.viewerbase.layoutManager.layoutTemplateName = 'gridLayout';
|
||||
OHIF.viewerbase.layoutManager.layoutProps = layoutProps;
|
||||
OHIF.viewerbase.layoutManager.updateViewports();
|
||||
|
||||
const $dropdown = instance.$('.layoutChooser');
|
||||
toggleDialog($dropdown);
|
||||
viewportUtils.toggleDialog($dropdown);
|
||||
}
|
||||
});
|
||||
+11
-10
@@ -1,3 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Meteor.startup(function() {
|
||||
@@ -8,43 +11,41 @@ Meteor.startup(function() {
|
||||
|
||||
var loadHandlerTimeout;
|
||||
|
||||
startLoadingHandler = function(element) {
|
||||
const startLoadingHandler = function(element) {
|
||||
clearTimeout(loadHandlerTimeout);
|
||||
loadHandlerTimeout = setTimeout(function() {
|
||||
console.log('startLoading');
|
||||
var elem = $(element);
|
||||
elem.siblings('.imageViewerErrorLoadingIndicator').css('display', 'none');
|
||||
elem.find('canvas').not('.magnifyTool').addClass("faded");
|
||||
elem.find('canvas').not('.magnifyTool').addClass('faded');
|
||||
elem.siblings('.imageViewerLoadingIndicator').css('display', 'block');
|
||||
}, OHIF.viewer.loadIndicatorDelay);
|
||||
};
|
||||
|
||||
doneLoadingHandler = function(element) {
|
||||
const doneLoadingHandler = function(element) {
|
||||
clearTimeout(loadHandlerTimeout);
|
||||
var elem = $(element);
|
||||
elem.siblings('.imageViewerErrorLoadingIndicator').css('display', 'none');
|
||||
elem.find('canvas').not('.magnifyTool').removeClass("faded");
|
||||
elem.find('canvas').not('.magnifyTool').removeClass('faded');
|
||||
elem.siblings('.imageViewerLoadingIndicator').css('display', 'none');
|
||||
};
|
||||
|
||||
errorLoadingHandler = function(element, imageId, error, source) {
|
||||
const errorLoadingHandler = function(element, imageId, error, source) {
|
||||
clearTimeout(loadHandlerTimeout);
|
||||
var elem = $(element);
|
||||
|
||||
// Could probably chain all of these, but this is more readable
|
||||
elem.find('canvas').not('.magnifyTool').removeClass("faded");
|
||||
elem.find('canvas').not('.magnifyTool').removeClass('faded');
|
||||
elem.siblings('.imageViewerLoadingIndicator').css('display', 'none');
|
||||
|
||||
// Don't display errors from the stackPrefetch tool
|
||||
if (source === "stackPrefetch") {
|
||||
if (source === 'stackPrefetch') {
|
||||
return;
|
||||
}
|
||||
|
||||
var errorLoadingIndicator = elem.siblings('.imageViewerErrorLoadingIndicator');
|
||||
errorLoadingIndicator.css('display', 'block');
|
||||
|
||||
var cleanedImageId = imageId;
|
||||
|
||||
// This is just used to expand upon some error messages that are sent
|
||||
// when things fail. An example is a network error throwing the error
|
||||
// which is only described as "network".
|
||||
@@ -57,7 +58,7 @@ errorLoadingHandler = function(element, imageId, error, source) {
|
||||
error = errorDetails[error];
|
||||
}
|
||||
|
||||
errorLoadingIndicator.find('.description').text("An error has occurred while loading image: " + cleanedImageId);
|
||||
errorLoadingIndicator.find('.description').text("An error has occurred while loading image: " + imageId);
|
||||
if (error) {
|
||||
errorLoadingIndicator.find('.details').text("Details: " + error);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { viewportUtils } from '../../../lib/viewportUtils';
|
||||
|
||||
Template.playClipButton.helpers({
|
||||
isPlaying: function() {
|
||||
return isPlaying();
|
||||
return viewportUtils.isPlaying();
|
||||
},
|
||||
disableButton() {
|
||||
return hasMultipleFrames();
|
||||
return viewportUtils.hasMultipleFrames();
|
||||
}
|
||||
});
|
||||
+5
-1
@@ -1,6 +1,10 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { Session } from 'meteor/session';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
|
||||
Template.studySeriesQuickSwitch.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
@@ -10,7 +14,7 @@ Template.studySeriesQuickSwitch.onCreated(() => {
|
||||
|
||||
// Gets the viewport data for the given viewport index
|
||||
instance.getViewportData = viewportIndex => {
|
||||
const layoutManager = window.layoutManager;
|
||||
const layoutManager = OHIF.viewerbase.layoutManager;
|
||||
return layoutManager && layoutManager.viewportData && layoutManager.viewportData[viewportIndex];
|
||||
};
|
||||
|
||||
|
||||
+3
-1
@@ -3,6 +3,8 @@ import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
import { OHIFError } from '../../../lib/classes/OHIFError';
|
||||
|
||||
Template.studyTimepointBrowser.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
@@ -36,7 +38,7 @@ Template.studyTimepointBrowser.onCreated(() => {
|
||||
|
||||
const notYetLoaded = StudyListStudies.findOne(query);
|
||||
if (!notYetLoaded) {
|
||||
throw 'No study data available for Study: ' + studyInstanceUid;
|
||||
throw new OHIFError(`No study data available for Study: ${studyInstanceUid}`);
|
||||
}
|
||||
|
||||
return notYetLoaded;
|
||||
|
||||
+2
-6
@@ -3,6 +3,7 @@ import { Template } from 'meteor/templating';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { sortingManager } from '../../../lib/sortingManager';
|
||||
|
||||
Template.studyTimepointStudy.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
@@ -16,11 +17,6 @@ Template.studyTimepointStudy.onCreated(() => {
|
||||
return isGlobal ? $(selector) : instance.$browser.find(selector);
|
||||
};
|
||||
|
||||
// Set all the studies with the same uid to loading state
|
||||
instance.setLoading = () => {
|
||||
|
||||
};
|
||||
|
||||
// Set the current study as selected in the studies list
|
||||
instance.select = (isQuickSwitch=false) => {
|
||||
const studyInstanceUid = instance.data.study.studyInstanceUid;
|
||||
@@ -110,7 +106,7 @@ Template.studyTimepointStudy.events({
|
||||
const $studies = instance.getStudyElement(true);
|
||||
$studies.trigger('loadStarted');
|
||||
getStudyMetadata(studyInstanceUid, study => {
|
||||
study.displaySets = createStacks(study);
|
||||
study.displaySets = sortingManager.getDisplaySets(study);
|
||||
instance.data.study = study;
|
||||
ViewerStudies.insert(study, () => {
|
||||
// To make sure studies are rendered in the DOM
|
||||
|
||||
+1
@@ -2,6 +2,7 @@ import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { toolManager } from '../../../lib/toolManager';
|
||||
|
||||
Template.toolbarSectionButton.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { unloadHandlers } from '../../../lib/unloadHandlers.js';
|
||||
// Local Modules
|
||||
import { toolManager } from '../../../lib/toolManager';
|
||||
import { unloadHandlers } from '../../../lib/unloadHandlers';
|
||||
import { hotkeyUtils } from '../../../lib/hotkeyUtils';
|
||||
import { ResizeViewportManager } from '../../../lib/classes/ResizeViewportManager';
|
||||
import { LayoutManager } from '../../../lib/classes/LayoutManager';
|
||||
|
||||
Meteor.startup(() => {
|
||||
// Create the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer('CornerstoneNewImage', cornerstoneTools.updateImageSynchronizer);
|
||||
|
||||
window.ResizeViewportManager = window.ResizeViewportManager || new ResizeViewportManager();
|
||||
});
|
||||
|
||||
Template.viewerMain.onCreated(() => {
|
||||
// Attach the Window resize listener
|
||||
@@ -8,23 +23,22 @@ Template.viewerMain.onCreated(() => {
|
||||
// and change it to jQuery._data(window, 'events')['resize'].
|
||||
// Otherwise this function will be probably overrided.
|
||||
// See cineDialog instance.setResizeHandler function
|
||||
window.addEventListener('resize', handleResize);
|
||||
window.addEventListener('resize', window.ResizeViewportManager.handleResize.bind(window.ResizeViewportManager));
|
||||
|
||||
// Add beforeUnload event handler to check for unsaved changes
|
||||
window.addEventListener('beforeunload', unloadHandlers.beforeUnload);
|
||||
|
||||
// Create the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer('CornerstoneNewImage', cornerstoneTools.updateImageSynchronizer);
|
||||
});
|
||||
|
||||
Template.viewerMain.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
HP.ProtocolStore.onReady(() => {
|
||||
instance.subscribe('hangingprotocols', () => {
|
||||
const { studies, currentTimepointId, measurementApi, timepointIds } = instance.data;
|
||||
const parentElement = instance.$('#layoutManagerTarget').get(0);
|
||||
window.layoutManager = new LayoutManager(parentElement, studies);
|
||||
|
||||
OHIF.viewerbase.layoutManager = new LayoutManager(parentElement, studies);
|
||||
|
||||
OHIF.viewerbase.layoutManager.updateViewports();
|
||||
// Default actions for Associated Studies
|
||||
if(currentTimepointId) {
|
||||
// Follow-up studies: same as the first measurement in the table
|
||||
@@ -73,18 +87,22 @@ Template.viewerMain.onRendered(() => {
|
||||
}
|
||||
|
||||
// Toggle Measurement Table
|
||||
instance.data.state.set('rightSidebar', 'measurements');
|
||||
if(instance.data.state) {
|
||||
instance.data.state.set('rightSidebar', 'measurements');
|
||||
}
|
||||
}
|
||||
// Hide as default for single study
|
||||
else {
|
||||
instance.data.state.set('rightSidebar', null);
|
||||
if(instance.data.state) {
|
||||
instance.data.state.set('rightSidebar', null);
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolEngine = new HP.ProtocolEngine(window.layoutManager, studies);
|
||||
HP.setEngine(ProtocolEngine);
|
||||
// ProtocolEngine = new HP.ProtocolEngine(OHIF.viewerbase.layoutManager, studies);
|
||||
// HP.setEngine(ProtocolEngine);
|
||||
|
||||
// Enable hotkeys
|
||||
enableHotkeys();
|
||||
hotkeyUtils.enableHotkeys();
|
||||
|
||||
Session.set('ViewerMainReady', Random.id());
|
||||
});
|
||||
@@ -94,7 +112,7 @@ Template.viewerMain.onDestroyed(() => {
|
||||
OHIF.log.info('viewerMain onDestroyed');
|
||||
|
||||
// Remove the Window resize listener
|
||||
window.removeEventListener('resize', handleResize);
|
||||
window.removeEventListener('resize', window.ResizeViewportManager.handleResize.bind(window.ResizeViewportManager));
|
||||
|
||||
// Remove beforeUnload event handler...
|
||||
window.removeEventListener('beforeunload', unloadHandlers.beforeUnload);
|
||||
@@ -102,6 +120,6 @@ Template.viewerMain.onDestroyed(() => {
|
||||
// Destroy the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer.destroy();
|
||||
|
||||
delete window.layoutManager;
|
||||
delete OHIF.viewerbase.layoutManager;
|
||||
delete ProtocolEngine;
|
||||
});
|
||||
+110
-202
@@ -1,253 +1,147 @@
|
||||
function getElementIfNotEmpty(viewportIndex) {
|
||||
// Meteor template helpers run more often than expected
|
||||
// They often seem to run just before the whole template is rendered
|
||||
// This meant that the onRendered event hadn't fired yet, so the
|
||||
// element wasn't enabled / set empty yet. The check here
|
||||
// for canvases under the 'enabled' element div is to prevent
|
||||
// 'undefined' errors from the helper functions
|
||||
|
||||
var imageViewerViewports = $('.imageViewerViewport'),
|
||||
element = imageViewerViewports.get(viewportIndex),
|
||||
canvases = imageViewerViewports.eq(viewportIndex).find('canvas');
|
||||
|
||||
if (!element || $(element).hasClass('empty') || canvases.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to make sure the element is enabled.
|
||||
try {
|
||||
var enabledElement = cornerstone.getEnabledElement(element);
|
||||
} catch(error) {
|
||||
return;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function getStackDataIfNotEmpty(viewportIndex) {
|
||||
const element = getElementIfNotEmpty(viewportIndex);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stackToolData = cornerstoneTools.getToolState(element, 'stack');
|
||||
if (!stackToolData ||
|
||||
!stackToolData.data ||
|
||||
!stackToolData.data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stack = stackToolData.data[0];
|
||||
if (!stack) {
|
||||
return;
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
function getPatient(property) {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
if (!this.imageId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var patient = cornerstoneTools.metaData.get('patient', this.imageId);
|
||||
if (!patient) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return patient[property];
|
||||
}
|
||||
|
||||
function getStudy(property) {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
if (!this.imageId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var study = cornerstoneTools.metaData.get('study', this.imageId);
|
||||
if (!study) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return study[property];
|
||||
}
|
||||
|
||||
function getSeries(property) {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
if (!this.imageId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var series = cornerstoneTools.metaData.get('series', this.imageId);
|
||||
if (!series) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return series[property];
|
||||
}
|
||||
|
||||
function getInstance(property) {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
if (!this.imageId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var instance = cornerstoneTools.metaData.get('instance', this.imageId);
|
||||
if (!instance) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return instance[property];
|
||||
}
|
||||
|
||||
function getTagDisplay(property) {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
if (!this.imageId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var instance = cornerstoneTools.metaData.get('tagDisplay', this.imageId);
|
||||
if (!instance) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return instance[property];
|
||||
}
|
||||
|
||||
function getImage(viewportIndex) {
|
||||
var element = getElementIfNotEmpty(viewportIndex);
|
||||
if (!element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var enabledElement;
|
||||
try {
|
||||
enabledElement = cornerstone.getEnabledElement(element);
|
||||
} catch(error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!enabledElement || !enabledElement.image) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return enabledElement.image;
|
||||
}
|
||||
|
||||
function formatDateTime(date, time) {
|
||||
return `${date} ${time}`;
|
||||
}
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { viewportOverlayUtils } from '../../../lib/viewportOverlayUtils';
|
||||
import { getElementIfNotEmpty } from '../../../lib/getElementIfNotEmpty';
|
||||
import { getStackDataIfNotEmpty } from '../../../lib/getStackDataIfNotEmpty';
|
||||
|
||||
Template.viewportOverlay.helpers({
|
||||
wwwc: function() {
|
||||
wwwc() {
|
||||
Session.get('CornerstoneImageRendered' + this.viewportIndex);
|
||||
var element = getElementIfNotEmpty(this.viewportIndex);
|
||||
|
||||
const element = getElementIfNotEmpty(this.viewportIndex);
|
||||
if (!element) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var viewport = cornerstone.getViewport(element);
|
||||
const viewport = cornerstone.getViewport(element);
|
||||
if (!viewport) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return 'W ' + viewport.voi.windowWidth.toFixed(0) + ' L ' + viewport.voi.windowCenter.toFixed(0);
|
||||
},
|
||||
zoom: function() {
|
||||
zoom() {
|
||||
Session.get('CornerstoneImageRendered' + this.viewportIndex);
|
||||
var element = getElementIfNotEmpty(this.viewportIndex);
|
||||
|
||||
const element = getElementIfNotEmpty(this.viewportIndex);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
var viewport = cornerstone.getViewport(element);
|
||||
const viewport = cornerstone.getViewport(element);
|
||||
if (!viewport) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (viewport.scale * 100.0);
|
||||
},
|
||||
imageDimensions: function() {
|
||||
imageDimensions() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
var image = getImage(this.viewportIndex);
|
||||
const image = viewportOverlayUtils.getImage(this.viewportIndex);
|
||||
if (!image) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return image.width + ' x ' + image.height;
|
||||
},
|
||||
patientName: function() {
|
||||
return getPatient.call(this, 'name');
|
||||
patientName() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'name');
|
||||
},
|
||||
patientId: function() {
|
||||
return getPatient.call(this, 'id');
|
||||
patientId() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'id');
|
||||
},
|
||||
patientBirthDate: function() {
|
||||
return getPatient.call(this, 'birthDate');
|
||||
patientBirthDate() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'birthDate');
|
||||
},
|
||||
patientSex: function() {
|
||||
return getPatient.call(this, 'sex');
|
||||
patientSex() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'sex');
|
||||
},
|
||||
studyDate: function() {
|
||||
return getStudy.call(this, 'studyDate');
|
||||
studyDate() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getStudy.call(this, 'studyDate');
|
||||
},
|
||||
studyTime: function() {
|
||||
return getStudy.call(this, 'studyTime');
|
||||
studyTime() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getStudy.call(this, 'studyTime');
|
||||
},
|
||||
studyDescription: function() {
|
||||
return getStudy.call(this, 'studyDescription');
|
||||
studyDescription() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getStudy.call(this, 'studyDescription');
|
||||
},
|
||||
seriesDescription: function() {
|
||||
return getSeries.call(this, 'seriesDescription');
|
||||
seriesDescription() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getSeries.call(this, 'seriesDescription');
|
||||
},
|
||||
frameRate: function() {
|
||||
var frameTime = getInstance.call(this, 'frameTime');
|
||||
frameRate() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
const frameTime = viewportOverlayUtils.getInstance.call(this, 'frameTime');
|
||||
if (!frameTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
var frameRate = 1000 / frameTime;
|
||||
|
||||
const frameRate = 1000 / frameTime;
|
||||
return frameRate.toFixed(1);
|
||||
},
|
||||
seriesNumber: function() {
|
||||
return getSeries.call(this, 'seriesNumber');
|
||||
seriesNumber() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getSeries.call(this, 'seriesNumber');
|
||||
},
|
||||
instanceNumber: function() {
|
||||
return getInstance.call(this, 'instanceNumber');
|
||||
instanceNumber() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'instanceNumber');
|
||||
},
|
||||
thickness() {
|
||||
// Displays Slice Thickness (0018,0050)
|
||||
return getInstance.call(this, 'sliceThickness');
|
||||
},
|
||||
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'sliceThickness');
|
||||
},
|
||||
location() {
|
||||
// Displays Slice Location (0020,1041), if present.
|
||||
// - Otherwise, displays Table Position (0018,9327)
|
||||
// - TODO: Otherwise, displays a value derived from Image Position (Patient) (0020,0032)
|
||||
const sliceLocation = getInstance.call(this, 'sliceLocation');
|
||||
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
const sliceLocation = viewportOverlayUtils.getInstance.call(this, 'sliceLocation');
|
||||
if (sliceLocation !== '') {
|
||||
return sliceLocation;
|
||||
}
|
||||
|
||||
const tablePosition = getInstance.call(this, 'tablePosition');
|
||||
const tablePosition = viewportOverlayUtils.getInstance.call(this, 'tablePosition');
|
||||
if (tablePosition !== '') {
|
||||
return tablePosition;
|
||||
}
|
||||
|
||||
return getInstance.call(this, 'imagePositionPatient');
|
||||
return viewportOverlayUtils.getInstance.call(this, 'imagePositionPatient');
|
||||
},
|
||||
|
||||
spacingBetweenSlices() {
|
||||
// Displays Spacing Between Slices (0018,0088), if present.
|
||||
|
||||
// TODO: Otherwise, displays a value derived from successive values
|
||||
// of Image Position (Patient) (0020,0032) perpendicular to
|
||||
// the Image Orientation (Patient) (0020,0037)
|
||||
return getInstance.call(this, 'spacingBetweenSlices');
|
||||
},
|
||||
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'spacingBetweenSlices');
|
||||
},
|
||||
compression() {
|
||||
// Displays whether or not lossy compression has been applied:
|
||||
//
|
||||
@@ -256,11 +150,12 @@ Template.viewportOverlay.helpers({
|
||||
// and Lossy Image Compression Method (0028,2114)
|
||||
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
if (!this.imageId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var instance = cornerstoneTools.metaData.get('instance', this.imageId);
|
||||
const instance = cornerstoneTools.metaData.get('instance', this.imageId);
|
||||
if (!instance) {
|
||||
return '';
|
||||
}
|
||||
@@ -274,43 +169,56 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return 'Lossless / Uncompressed';
|
||||
},
|
||||
|
||||
tagDisplayLeftOnly: function() {
|
||||
return getTagDisplay.call(this, 'side') === 'L';
|
||||
},
|
||||
tagDisplayRightOnly: function() {
|
||||
return getTagDisplay.call(this, 'side') === 'R';
|
||||
},
|
||||
tagDisplaySpecified: function() {
|
||||
return getTagDisplay.call(this, 'side');
|
||||
},
|
||||
imageIndex: function() {
|
||||
tagDisplayLeftOnly() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
var stack = getStackDataIfNotEmpty(this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'L';
|
||||
},
|
||||
tagDisplayRightOnly() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'R';
|
||||
},
|
||||
tagDisplaySpecified() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getTagDisplay.call(this, 'side');
|
||||
},
|
||||
imageNumber() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'number');
|
||||
},
|
||||
imageIndex() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
const stack = getStackDataIfNotEmpty(this.viewportIndex);
|
||||
if (!stack || stack.currentImageIdIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
return stack.currentImageIdIndex + 1;
|
||||
},
|
||||
numImages: function() {
|
||||
numImages() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
var stack = getStackDataIfNotEmpty(this.viewportIndex);
|
||||
|
||||
const stack = getStackDataIfNotEmpty(this.viewportIndex);
|
||||
if (!stack || !stack.imageIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
return stack.imageIds.length;
|
||||
},
|
||||
prior: function() {
|
||||
prior() {
|
||||
// This helper is updated whenever a new image is displayed in the viewport
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
if (!this.imageId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure there are more than two studies loaded in the viewer
|
||||
var viewportStudies = ViewerStudies.find();
|
||||
const viewportStudies = ViewerStudies.find();
|
||||
if (viewportStudies.count() < 2) {
|
||||
return;
|
||||
}
|
||||
@@ -319,18 +227,18 @@ Template.viewportOverlay.helpers({
|
||||
// that we can obtain the oldest study as the first element of the array
|
||||
//
|
||||
// TODO= Find out if we should encode studyDate as a Date in the ViewerStudies Collection
|
||||
var viewportStudiesArray = _.sortBy(viewportStudies.fetch(), function(study) {
|
||||
return formatDateTime(study.studyDate, study.studyTime);
|
||||
const viewportStudiesArray = _.sortBy(viewportStudies.fetch(), function(study) {
|
||||
return viewportOverlayUtils.formatDateTime(study.studyDate, study.studyTime);
|
||||
});
|
||||
|
||||
// Get study data
|
||||
var study = cornerstoneTools.metaData.get('study', this.imageId);
|
||||
const study = cornerstoneTools.metaData.get('study', this.imageId);
|
||||
if (!study) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oldestStudy = viewportStudiesArray[0];
|
||||
if (formatDateTime(study.studyDate, study.studyTime) <= formatDateTime(oldestStudy.studyDate, oldestStudy.studyTime)) {
|
||||
const oldestStudy = viewportStudiesArray[0];
|
||||
if (viewportOverlayUtils.formatDateTime(study.studyDate, study.studyTime) <= viewportOverlayUtils.formatDateTime(oldestStudy.studyDate, oldestStudy.studyTime)) {
|
||||
return 'Prior';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user