Most JS files, all helpers and simple reconciliations
This commit is contained in:
parent
21400c5836
commit
9e69c43dda
@ -1,5 +1,6 @@
|
|||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { Session } from 'meteor/session';
|
import { Session } from 'meteor/session';
|
||||||
|
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||||
|
|
||||||
Template.toolbarSection.helpers({
|
Template.toolbarSection.helpers({
|
||||||
// Returns true if the view shall be split in two viewports
|
// Returns true if the view shall be split in two viewports
|
||||||
@ -141,7 +142,7 @@ Template.toolbarSection.helpers({
|
|||||||
title: 'CINE',
|
title: 'CINE',
|
||||||
classes: 'imageViewerCommand',
|
classes: 'imageViewerCommand',
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-cineplay-toggle',
|
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-cineplay-toggle',
|
||||||
disableFunction: hasMultipleFrames
|
disableFunction: Viewerbase.viewportUtils.hasMultipleFrames
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttonData = [];
|
const buttonData = [];
|
||||||
@ -168,11 +169,11 @@ Template.toolbarSection.helpers({
|
|||||||
});
|
});
|
||||||
|
|
||||||
buttonData.push({
|
buttonData.push({
|
||||||
id: 'link',
|
id: 'linkStackScroll',
|
||||||
title: 'Link',
|
title: 'Link',
|
||||||
classes: 'imageViewerCommand toolbarSectionButton nonAutoDisableState',
|
classes: 'imageViewerCommand toolbarSectionButton nonAutoDisableState',
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-link',
|
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-link',
|
||||||
disableFunction: isStackScrollLinkingDisabled
|
disableFunction: Viewerbase.viewportUtils.isStackScrollLinkingDisabled
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonData.push({
|
buttonData.push({
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Template } from 'meteor/templating';
|
|||||||
import { Session } from 'meteor/session';
|
import { Session } from 'meteor/session';
|
||||||
import { ReactiveDict } from 'meteor/reactive-dict';
|
import { ReactiveDict } from 'meteor/reactive-dict';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import 'meteor/ohif:viewerbase';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
Session.set('ViewerMainReady', false);
|
Session.set('ViewerMainReady', false);
|
||||||
@ -32,15 +33,15 @@ Template.viewer.onCreated(() => {
|
|||||||
toolManager.setActiveTool('nonTarget');
|
toolManager.setActiveTool('nonTarget');
|
||||||
},
|
},
|
||||||
// Viewport functions
|
// Viewport functions
|
||||||
toggleCineDialog,
|
toggleCineDialog: OHIF.viewerbase.viewportUtils.toggleCineDialog,
|
||||||
clearTools,
|
clearTools: OHIF.viewerbase.viewportUtils.clearTools,
|
||||||
resetViewport,
|
resetViewport: OHIF.viewerbase.viewportUtils.resetViewport,
|
||||||
invert,
|
invert: OHIF.viewerbase.viewportUtils.invert,
|
||||||
flipV,
|
flipV: OHIF.viewerbase.viewportUtils.flipV,
|
||||||
flipH,
|
flipH: OHIF.viewerbase.viewportUtils.flipH,
|
||||||
rotateL,
|
rotateL: OHIF.viewerbase.viewportUtils.rotateL,
|
||||||
rotateR,
|
rotateR: OHIF.viewerbase.viewportUtils.rotateR,
|
||||||
link
|
linkStackScroll: OHIF.viewerbase.viewportUtils.linkStackScroll
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ViewerData[contentId].loadedSeriesData) {
|
if (ViewerData[contentId].loadedSeriesData) {
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { Random } from 'meteor/random';
|
||||||
|
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import 'meteor/ohif:viewerbase';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the Array prototype with a Swap function
|
* Extend the Array prototype with a Swap function
|
||||||
* so we can swap stages more easily
|
* so we can swap stages more easily
|
||||||
*/
|
*/
|
||||||
Array.prototype.move = function(oldIndex, newIndex) {
|
Array.prototype.move = function(oldIndex, newIndex) {
|
||||||
var value = this[oldIndex];
|
const value = this[oldIndex];
|
||||||
|
|
||||||
newIndex = Math.max(0, newIndex);
|
newIndex = Math.max(0, newIndex);
|
||||||
newIndex = Math.min(this.length, newIndex);
|
newIndex = Math.min(this.length, newIndex);
|
||||||
@ -22,13 +29,13 @@ Array.prototype.move = function(oldIndex, newIndex) {
|
|||||||
* @returns {number} The index of the specified stage within the Protocol,
|
* @returns {number} The index of the specified stage within the Protocol,
|
||||||
* or undefined if it is not present.
|
* or undefined if it is not present.
|
||||||
*/
|
*/
|
||||||
function getStageIndex(protocol, id) {
|
const getStageIndex = (protocol, id) => {
|
||||||
var stageIndex;
|
let stageIndex;
|
||||||
if (!protocol || !protocol.stages) {
|
if (!protocol || !protocol.stages) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol.stages.forEach(function(stage, index) {
|
protocol.stages.forEach((stage, index) => {
|
||||||
if (stage.id === id) {
|
if (stage.id === id) {
|
||||||
stageIndex = index;
|
stageIndex = index;
|
||||||
return false;
|
return false;
|
||||||
@ -36,7 +43,7 @@ function getStageIndex(protocol, id) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return stageIndex;
|
return stageIndex;
|
||||||
}
|
};
|
||||||
|
|
||||||
Template.stageSortable.helpers({
|
Template.stageSortable.helpers({
|
||||||
/**
|
/**
|
||||||
@ -44,7 +51,7 @@ Template.stageSortable.helpers({
|
|||||||
*
|
*
|
||||||
* @returns {boolean} Whether or not the stage is currently being displayed
|
* @returns {boolean} Whether or not the stage is currently being displayed
|
||||||
*/
|
*/
|
||||||
isActiveStage: function() {
|
isActiveStage() {
|
||||||
// Rerun this function every time the layout manager has been updated
|
// Rerun this function every time the layout manager has been updated
|
||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
@ -53,7 +60,7 @@ Template.stageSortable.helpers({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentStage = ProtocolEngine.getCurrentStageModel();
|
const currentStage = ProtocolEngine.getCurrentStageModel();
|
||||||
if (!currentStage) {
|
if (!currentStage) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -66,8 +73,8 @@ Template.stageSortable.helpers({
|
|||||||
*
|
*
|
||||||
* @returns {number|*}
|
* @returns {number|*}
|
||||||
*/
|
*/
|
||||||
stageLabel: function() {
|
stageLabel() {
|
||||||
var stage = this;
|
const stage = this;
|
||||||
|
|
||||||
// If no Protocol Engine has been defined yet, stop here to prevent errors
|
// If no Protocol Engine has been defined yet, stop here to prevent errors
|
||||||
if (!ProtocolEngine) {
|
if (!ProtocolEngine) {
|
||||||
@ -75,10 +82,10 @@ Template.stageSortable.helpers({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the last saved copy of the current protocol
|
// Retrieve the last saved copy of the current protocol
|
||||||
var lastSavedCopy = HP.ProtocolStore.getProtocol(ProtocolEngine.protocol.id);
|
const lastSavedCopy = HangingProtocols.findOne(ProtocolEngine.protocol._id);
|
||||||
|
|
||||||
// Try to find the index of this stage in the previously saved copy
|
// Try to find the index of this stage in the previously saved copy
|
||||||
var stageIndex = getStageIndex(lastSavedCopy, stage.id);
|
let stageIndex = getStageIndex(lastSavedCopy, stage.id);
|
||||||
|
|
||||||
// If the stage is new, and therefore wasn't present in the last save,
|
// If the stage is new, and therefore wasn't present in the last save,
|
||||||
// retrieve it's index in the array of new stage ids and use that for
|
// retrieve it's index in the array of new stage ids and use that for
|
||||||
@ -88,11 +95,11 @@ Template.stageSortable.helpers({
|
|||||||
Session.get('timeAgoVariable');
|
Session.get('timeAgoVariable');
|
||||||
|
|
||||||
// Find the index of the stage in the array of newly created stage IDs
|
// Find the index of the stage in the array of newly created stage IDs
|
||||||
var newStageNumber = ProtocolEngine.newStageIds.indexOf(stage.id) + 1;
|
const newStageNumber = ProtocolEngine.newStageIds.indexOf(stage.id) + 1;
|
||||||
|
|
||||||
// Use Moment.js to format the createdDate of this stage relative to the
|
// Use Moment.js to format the createdDate of this stage relative to the
|
||||||
// current time
|
// current time
|
||||||
var dateCreatedFromNow = moment(stage.createdDate).fromNow();
|
const dateCreatedFromNow = moment(stage.createdDate).fromNow();
|
||||||
|
|
||||||
// Return the label for the new stage,
|
// Return the label for the new stage,
|
||||||
// e.g. "New Stage 1 (created a few seconds ago)"
|
// e.g. "New Stage 1 (created a few seconds ago)"
|
||||||
@ -108,7 +115,7 @@ Template.stageSortable.helpers({
|
|||||||
*
|
*
|
||||||
* @returns {boolean} Whether or not a later stage exists
|
* @returns {boolean} Whether or not a later stage exists
|
||||||
*/
|
*/
|
||||||
isNextAvailable: function() {
|
isNextAvailable() {
|
||||||
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
@ -125,7 +132,7 @@ Template.stageSortable.helpers({
|
|||||||
*
|
*
|
||||||
* @returns {boolean} Whether or not an earlier stage exists
|
* @returns {boolean} Whether or not an earlier stage exists
|
||||||
*/
|
*/
|
||||||
isPreviousAvailable: function() {
|
isPreviousAvailable() {
|
||||||
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
// Run this helper whenever the ProtocolEngine / LayoutManager has changed
|
||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
@ -143,9 +150,9 @@ Template.stageSortable.events({
|
|||||||
/**
|
/**
|
||||||
* Displays a stage when its title is clicked
|
* Displays a stage when its title is clicked
|
||||||
*/
|
*/
|
||||||
'click .sortable-item span': function() {
|
'click .sortable-item span'() {
|
||||||
// Retrieve the index of this stage in the display set sequences
|
// Retrieve the index of this stage in the display set sequences
|
||||||
var stageIndex = getStageIndex(ProtocolEngine.protocol, this.id);
|
const stageIndex = getStageIndex(ProtocolEngine.protocol, this.id);
|
||||||
|
|
||||||
// Display the selected stage
|
// Display the selected stage
|
||||||
ProtocolEngine.setCurrentProtocolStage(stageIndex);
|
ProtocolEngine.setCurrentProtocolStage(stageIndex);
|
||||||
@ -154,12 +161,12 @@ Template.stageSortable.events({
|
|||||||
* Creates a new stage and adds it to the currently loaded Protocol at
|
* Creates a new stage and adds it to the currently loaded Protocol at
|
||||||
* the end of the display set sequence
|
* the end of the display set sequence
|
||||||
*/
|
*/
|
||||||
'click #addStage': function() {
|
'click #addStage'() {
|
||||||
// Retrieve the model describing the current stage
|
// Retrieve the model describing the current stage
|
||||||
var stage = ProtocolEngine.getCurrentStageModel();
|
const stage = ProtocolEngine.getCurrentStageModel();
|
||||||
|
|
||||||
// Clone this stage to create a new stage
|
// Clone this stage to create a new stage
|
||||||
var newStage = stage.createClone();
|
const newStage = stage.createClone();
|
||||||
|
|
||||||
// Remove the stage's name if it has one
|
// Remove the stage's name if it has one
|
||||||
delete newStage.name;
|
delete newStage.name;
|
||||||
@ -171,7 +178,7 @@ Template.stageSortable.events({
|
|||||||
ProtocolEngine.newStageIds.push(newStage.id);
|
ProtocolEngine.newStageIds.push(newStage.id);
|
||||||
|
|
||||||
// Calculate the index of the last stage in the display set sequence
|
// Calculate the index of the last stage in the display set sequence
|
||||||
var stageIndex = ProtocolEngine.protocol.stages.length - 1;
|
const stageIndex = ProtocolEngine.protocol.stages.length - 1;
|
||||||
|
|
||||||
// Switch to the last stage in the display set sequence
|
// Switch to the last stage in the display set sequence
|
||||||
ProtocolEngine.setCurrentProtocolStage(stageIndex);
|
ProtocolEngine.setCurrentProtocolStage(stageIndex);
|
||||||
@ -181,22 +188,22 @@ Template.stageSortable.events({
|
|||||||
* the stages array. If it is the currently active stage, the current stage is
|
* the stages array. If it is the currently active stage, the current stage is
|
||||||
* set to one stage earlier in the display set sequence.
|
* set to one stage earlier in the display set sequence.
|
||||||
*/
|
*/
|
||||||
'click .deleteStage': function() {
|
'click .deleteStage'() {
|
||||||
// If this is the only stage in the Protocol, stop here
|
// If this is the only stage in the Protocol, stop here
|
||||||
if (ProtocolEngine.protocol.stages.length === 1) {
|
if (ProtocolEngine.protocol.stages.length === 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var stageId = this.id;
|
const stageId = this.id;
|
||||||
|
|
||||||
var options = {
|
const options = {
|
||||||
title: 'Remove Protocol Stage',
|
title: 'Remove Protocol Stage',
|
||||||
text: 'Are you sure you would like to remove this Protocol Stage? This cannot be reversed.'
|
text: 'Are you sure you would like to remove this Protocol Stage? This cannot be reversed.'
|
||||||
};
|
};
|
||||||
|
|
||||||
showConfirmDialog(function() {
|
OHIF.viewerbase.showConfirmDialog(() => {
|
||||||
// Retrieve the index of this stage in the display set sequences
|
// Retrieve the index of this stage in the display set sequences
|
||||||
var stageIndex = getStageIndex(ProtocolEngine.protocol, stageId);
|
const stageIndex = getStageIndex(ProtocolEngine.protocol, stageId);
|
||||||
|
|
||||||
// Remove it from the display set sequence
|
// Remove it from the display set sequence
|
||||||
ProtocolEngine.protocol.stages.splice(stageIndex, 1);
|
ProtocolEngine.protocol.stages.splice(stageIndex, 1);
|
||||||
@ -204,7 +211,7 @@ Template.stageSortable.events({
|
|||||||
// If we have removed the currently active stage, switch to the one before it
|
// If we have removed the currently active stage, switch to the one before it
|
||||||
if (ProtocolEngine.stage === stageIndex) {
|
if (ProtocolEngine.stage === stageIndex) {
|
||||||
// Make sure we don't try to switch to a stage index below zero
|
// Make sure we don't try to switch to a stage index below zero
|
||||||
var newStageIndex = Math.max(stageIndex - 1, 0);
|
const newStageIndex = Math.max(stageIndex - 1, 0);
|
||||||
|
|
||||||
// Display the new stage
|
// Display the new stage
|
||||||
ProtocolEngine.setCurrentProtocolStage(newStageIndex);
|
ProtocolEngine.setCurrentProtocolStage(newStageIndex);
|
||||||
@ -215,10 +222,10 @@ Template.stageSortable.events({
|
|||||||
}, options);
|
}, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
'click .moveStageUp': function() {
|
'click .moveStageUp'() {
|
||||||
// Get the old and new indices following a 'sort' event
|
// Get the old and new indices following a 'sort' event
|
||||||
var oldIndex = ProtocolEngine.stage;
|
const oldIndex = ProtocolEngine.stage;
|
||||||
var newIndex = Math.max(ProtocolEngine.stage - 1, 0);
|
const newIndex = Math.max(ProtocolEngine.stage - 1, 0);
|
||||||
|
|
||||||
if (oldIndex === newIndex) {
|
if (oldIndex === newIndex) {
|
||||||
return;
|
return;
|
||||||
@ -235,10 +242,10 @@ Template.stageSortable.events({
|
|||||||
// Update the Session variable to the UI re-renders
|
// Update the Session variable to the UI re-renders
|
||||||
Session.set('LayoutManagerUpdated', Random.id());
|
Session.set('LayoutManagerUpdated', Random.id());
|
||||||
},
|
},
|
||||||
'click .moveStageDown': function() {
|
'click .moveStageDown'() {
|
||||||
// Get the old and new indices following a 'sort' event
|
// Get the old and new indices following a 'sort' event
|
||||||
var oldIndex = ProtocolEngine.stage;
|
const oldIndex = ProtocolEngine.stage;
|
||||||
var newIndex = Math.min(ProtocolEngine.stage + 1, ProtocolEngine.protocol.stages.length - 1);
|
const newIndex = Math.min(ProtocolEngine.stage + 1, ProtocolEngine.protocol.stages.length - 1);
|
||||||
|
|
||||||
if (oldIndex === newIndex) {
|
if (oldIndex === newIndex) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
var keys = {
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
|
||||||
|
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||||
|
|
||||||
|
const keys = {
|
||||||
ESC: 27,
|
ESC: 27,
|
||||||
ENTER: 13
|
ENTER: 13
|
||||||
};
|
};
|
||||||
@ -9,7 +15,7 @@ var keys = {
|
|||||||
*
|
*
|
||||||
* @param dialog The DOM element of the dialog to close
|
* @param dialog The DOM element of the dialog to close
|
||||||
*/
|
*/
|
||||||
function closeHandler(dialog) {
|
const closeHandler = dialog => {
|
||||||
// Hide the lesion dialog
|
// Hide the lesion dialog
|
||||||
$(dialog).css('display', 'none');
|
$(dialog).css('display', 'none');
|
||||||
|
|
||||||
@ -17,8 +23,8 @@ function closeHandler(dialog) {
|
|||||||
$('.removableBackdrop').remove();
|
$('.removableBackdrop').remove();
|
||||||
|
|
||||||
// Restore the focus to the active viewport
|
// Restore the focus to the active viewport
|
||||||
setFocusToActiveViewport();
|
Viewerbase.setFocusToActiveViewport();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays and updates the UI of the Text Entry Dialog given a new title,
|
* Displays and updates the UI of the Text Entry Dialog given a new title,
|
||||||
@ -30,10 +36,10 @@ function closeHandler(dialog) {
|
|||||||
*/
|
*/
|
||||||
openTextEntryDialog = function(title, instructions, currentValue, doneCallback) {
|
openTextEntryDialog = function(title, instructions, currentValue, doneCallback) {
|
||||||
// Get the lesion location dialog
|
// Get the lesion location dialog
|
||||||
var dialog = $('.textEntryDialog');
|
const dialog = $('.textEntryDialog');
|
||||||
|
|
||||||
// Clear any input that is still on the page
|
// Clear any input that is still on the page
|
||||||
var currentValueInput = dialog.find('input.currentValue');
|
const currentValueInput = dialog.find('input.currentValue');
|
||||||
currentValueInput.val(currentValue);
|
currentValueInput.val(currentValue);
|
||||||
|
|
||||||
// Store the Dialog DOM data, rule level and rule in the template data
|
// Store the Dialog DOM data, rule level and rule in the template data
|
||||||
@ -49,10 +55,10 @@ openTextEntryDialog = function(title, instructions, currentValue, doneCallback)
|
|||||||
dialog.css('display', 'block');
|
dialog.css('display', 'block');
|
||||||
|
|
||||||
// Show the backdrop
|
// Show the backdrop
|
||||||
UI.render(Template.removableBackdrop, document.body);
|
Blaze.render(Template.removableBackdrop, document.body);
|
||||||
|
|
||||||
// Make sure the context menu is closed when the user clicks away
|
// Make sure the context menu is closed when the user clicks away
|
||||||
$('.removableBackdrop').one('mousedown touchstart', function() {
|
$('.removableBackdrop').one('mousedown touchstart', () => {
|
||||||
closeHandler(dialog);
|
closeHandler(dialog);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -68,17 +74,17 @@ Template.textEntryDialog.events({
|
|||||||
* Save the user-specified text
|
* Save the user-specified text
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
'click .save': function() {
|
'click .save'() {
|
||||||
// Retrieve the input properties to the template
|
// Retrieve the input properties to the template
|
||||||
var dialog = Template.textEntryDialog.dialog;
|
const dialog = Template.textEntryDialog.dialog;
|
||||||
var currentValue = dialog.find('input.currentValue').val();
|
const currentValue = dialog.find('input.currentValue').val();
|
||||||
|
|
||||||
// If currentValue input is undefined, prevent saving this rule
|
// If currentValue input is undefined, prevent saving this rule
|
||||||
if (currentValue === undefined) {
|
if (currentValue === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var doneCallback = Template.textEntryDialog.doneCallback;
|
const doneCallback = Template.textEntryDialog.doneCallback;
|
||||||
if (doneCallback) {
|
if (doneCallback) {
|
||||||
doneCallback(currentValue);
|
doneCallback(currentValue);
|
||||||
}
|
}
|
||||||
@ -89,7 +95,7 @@ Template.textEntryDialog.events({
|
|||||||
/**
|
/**
|
||||||
* Allow the user to click the Cancel button to close the dialog
|
* Allow the user to click the Cancel button to close the dialog
|
||||||
*/
|
*/
|
||||||
'click .cancel': function() {
|
'click .cancel'() {
|
||||||
closeHandler(Template.textEntryDialog.dialog);
|
closeHandler(Template.textEntryDialog.dialog);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -98,22 +104,22 @@ Template.textEntryDialog.events({
|
|||||||
* @param event The Keydown event details
|
* @param event The Keydown event details
|
||||||
* @returns {boolean} Return false to prevent bubbling of the event
|
* @returns {boolean} Return false to prevent bubbling of the event
|
||||||
*/
|
*/
|
||||||
'keydown .textEntryDialog': function(event) {
|
'keydown .textEntryDialog'(event) {
|
||||||
var dialog = Template.textEntryDialog.dialog;
|
const dialog = Template.textEntryDialog.dialog;
|
||||||
|
|
||||||
// If Esc key is pressed, close the dialog
|
// If Esc key is pressed, close the dialog
|
||||||
if (event.which === keys.ESC) {
|
if (event.which === keys.ESC) {
|
||||||
closeHandler(dialog);
|
closeHandler(dialog);
|
||||||
return false;
|
return false;
|
||||||
} else if (event.which === keys.ENTER) {
|
} else if (event.which === keys.ENTER) {
|
||||||
var currentValue = dialog.find('input.currentValue').val();
|
const currentValue = dialog.find('input.currentValue').val();
|
||||||
|
|
||||||
// If currentValue input is undefined, prevent saving this rule
|
// If currentValue input is undefined, prevent saving this rule
|
||||||
if (currentValue === undefined) {
|
if (currentValue === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var doneCallback = Template.textEntryDialog.doneCallback;
|
const doneCallback = Template.textEntryDialog.doneCallback;
|
||||||
if (doneCallback) {
|
if (doneCallback) {
|
||||||
doneCallback(currentValue);
|
doneCallback(currentValue);
|
||||||
}
|
}
|
||||||
@ -128,9 +134,9 @@ Template.textEntryDialog.events({
|
|||||||
* @param event The Change event for the input
|
* @param event The Change event for the input
|
||||||
* @param template The current template context
|
* @param template The current template context
|
||||||
*/
|
*/
|
||||||
'change input.currentValue': function(event, template) {
|
'change input.currentValue'(event, template) {
|
||||||
// Get the DOM element representing the input box
|
// Get the DOM element representing the input box
|
||||||
var input = $(event.currentTarget);
|
const input = $(event.currentTarget);
|
||||||
|
|
||||||
// Update the template data with the current value
|
// Update the template data with the current value
|
||||||
Template.textEntryDialog.currentValue = input.val();
|
Template.textEntryDialog.currentValue = input.val();
|
||||||
|
|||||||
@ -189,8 +189,8 @@ var dialogPolyfill = (function() {
|
|||||||
|
|
||||||
dialogPolyfill.registerDialog = function(element) {
|
dialogPolyfill.registerDialog = function(element) {
|
||||||
if (element.show) {
|
if (element.show) {
|
||||||
console.warn("This browser already supports <dialog>, the polyfill " +
|
// console.warn("This browser already supports <dialog>, the polyfill " +
|
||||||
"may not work correctly.");
|
// "may not work correctly.");
|
||||||
}
|
}
|
||||||
element.show = dialogPolyfill.showDialog.bind(element, false);
|
element.show = dialogPolyfill.showDialog.bind(element, false);
|
||||||
element.showModal = dialogPolyfill.showDialog.bind(element, true);
|
element.showModal = dialogPolyfill.showDialog.bind(element, true);
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { Tracker } from 'meteor/tracker';
|
import { Tracker } from 'meteor/tracker';
|
||||||
import { Session } from 'meteor/session';
|
import { Session } from 'meteor/session';
|
||||||
|
// OHIF Modules
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
// Local Modules
|
||||||
|
import { getImageId } from '../../../lib/getImageId.js';
|
||||||
|
|
||||||
Template.imageThumbnail.onCreated(() => {
|
Template.imageThumbnail.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
@ -26,6 +30,10 @@ Template.imageThumbnail.onRendered(() => {
|
|||||||
const element = $element.get(0);
|
const element = $element.get(0);
|
||||||
|
|
||||||
instance.refreshImage = () => {
|
instance.refreshImage = () => {
|
||||||
|
if (!element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Disable cornerstone for thumbnail element and remove its canvas
|
// Disable cornerstone for thumbnail element and remove its canvas
|
||||||
cornerstone.disable(element);
|
cornerstone.disable(element);
|
||||||
|
|
||||||
@ -75,7 +83,9 @@ Template.imageThumbnail.onDestroyed(() => {
|
|||||||
const $element = $parent.find('.imageThumbnailCanvas');
|
const $element = $parent.find('.imageThumbnailCanvas');
|
||||||
const element = $element.get(0);
|
const element = $element.get(0);
|
||||||
|
|
||||||
cornerstone.disable(element);
|
if (element) {
|
||||||
|
cornerstone.disable(element);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.imageThumbnail.helpers({
|
Template.imageThumbnail.helpers({
|
||||||
|
|||||||
@ -1,202 +1,9 @@
|
|||||||
const cloneElement = (element, targetId) => {
|
import { Template } from 'meteor/templating';
|
||||||
// Clone the DOM element
|
import { _ } from 'meteor/underscore';
|
||||||
const clone = element.cloneNode(true);
|
import { Session } from 'meteor/session';
|
||||||
|
|
||||||
// Find any canvas children to clone
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
const clonedCanvases = $(clone).find('canvas');
|
import { thumbnailDragHandlers } from '../../../lib/thumbnailDragHandlers';
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
Template.thumbnailEntry.onCreated(() => {
|
Template.thumbnailEntry.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
@ -209,16 +16,16 @@ Template.thumbnailEntry.events({
|
|||||||
// Event handlers for drag and drop
|
// Event handlers for drag and drop
|
||||||
'touchstart .thumbnailEntry, mousedown .thumbnailEntry'(event, instance) {
|
'touchstart .thumbnailEntry, mousedown .thumbnailEntry'(event, instance) {
|
||||||
const data = instance.data.thumbnail.stack;
|
const data = instance.data.thumbnail.stack;
|
||||||
instance.isDragAndDrop && thumbnailDragStartHandler(event, data);
|
instance.isDragAndDrop && thumbnailDragHandlers.thumbnailDragStartHandler(event, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
'touchmove .thumbnailEntry'(event, instance) {
|
'touchmove .thumbnailEntry'(event, instance) {
|
||||||
instance.isDragAndDrop && thumbnailDragHandler(event);
|
instance.isDragAndDrop && thumbnailDragHandlers.thumbnailDragHandler(event);
|
||||||
},
|
},
|
||||||
|
|
||||||
'touchend .thumbnailEntry'(event, instance) {
|
'touchend .thumbnailEntry'(event, instance) {
|
||||||
const data = instance.data.thumbnail.stack;
|
const data = instance.data.thumbnail.stack;
|
||||||
instance.isDragAndDrop && thumbnailDragEndHandler(event, data);
|
instance.isDragAndDrop && thumbnailDragHandlers.thumbnailDragEndHandler(event, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Event handlers for click (quick switch)
|
// Event handlers for click (quick switch)
|
||||||
@ -228,7 +35,7 @@ Template.thumbnailEntry.events({
|
|||||||
const data = instance.data.thumbnail.stack;
|
const data = instance.data.thumbnail.stack;
|
||||||
|
|
||||||
// Rerender the viewport using the clicked thumbnail data
|
// 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;
|
const data = instance.data.thumbnail.stack;
|
||||||
|
|
||||||
// Rerender the viewport using the clicked thumbnail data
|
// Rerender the viewport using the clicked thumbnail data
|
||||||
window.layoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, data);
|
OHIF.viewerbase.layoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -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(() => {
|
Template.annotationDialogs.onRendered(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
const dialogIds = ['annotationDialog', 'relabelAnnotationDialog'];
|
const dialogIds = ['annotationDialog', 'relabelAnnotationDialog'];
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
|
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
import { Session } from 'meteor/session';
|
import { Session } from 'meteor/session';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
import { $ } from 'meteor/jquery';
|
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(() => {
|
Template.cineDialog.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
@ -34,18 +37,15 @@ Template.cineDialog.onCreated(() => {
|
|||||||
OHIF.viewer.cine.framesPerSecond = rate;
|
OHIF.viewer.cine.framesPerSecond = rate;
|
||||||
|
|
||||||
// Update playClip toolData for this imageId
|
// Update playClip toolData for this imageId
|
||||||
const element = getActiveViewportElement();
|
const element = viewportUtils.getActiveViewportElement();
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
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 the movie is playing, stop/start to update the framerate
|
||||||
if (isPlaying()) {
|
if (viewportUtils.isPlaying()) {
|
||||||
cornerstoneTools.stopClip(element);
|
cornerstoneTools.stopClip(element);
|
||||||
cornerstoneTools.playClip(element);
|
cornerstoneTools.playClip(element, OHIF.viewer.cine.framesPerSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
Session.set('UpdateCINE', Random.id());
|
Session.set('UpdateCINE', Random.id());
|
||||||
@ -55,7 +55,7 @@ Template.cineDialog.onCreated(() => {
|
|||||||
instance.api = {
|
instance.api = {
|
||||||
displaySetPrevious: () => OHIF.viewer.moveDisplaySets(false),
|
displaySetPrevious: () => OHIF.viewer.moveDisplaySets(false),
|
||||||
displaySetNext: () => OHIF.viewer.moveDisplaySets(true),
|
displaySetNext: () => OHIF.viewer.moveDisplaySets(true),
|
||||||
cineToggle: () => toggleCinePlay(),
|
cineToggle: () => viewportUtils.toggleCinePlay(),
|
||||||
cineFirst: () => switchToImageByIndex(0),
|
cineFirst: () => switchToImageByIndex(0),
|
||||||
cineLast: () => switchToImageByIndex(-1),
|
cineLast: () => switchToImageByIndex(-1),
|
||||||
cinePrevious: () => switchToImageRelative(-1),
|
cinePrevious: () => switchToImageRelative(-1),
|
||||||
@ -80,13 +80,19 @@ Template.cineDialog.onCreated(() => {
|
|||||||
|
|
||||||
Tracker.afterFlush(() => {
|
Tracker.afterFlush(() => {
|
||||||
// Get the active viewportElement
|
// Get the active viewportElement
|
||||||
const element = getActiveViewportElement();
|
const element = viewportUtils.getActiveViewportElement();
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if playClip tool has been initialized...
|
||||||
|
const playClipData = cornerstoneTools.getToolState(element, 'playClip');
|
||||||
|
if (!playClipData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the cornerstone playClip tool data
|
// Get the cornerstone playClip tool data
|
||||||
const toolData = cornerstoneTools.getToolState(element, 'playClip').data[0];
|
const toolData = playClipData.data[0];
|
||||||
|
|
||||||
// Get the cine object
|
// Get the cine object
|
||||||
const cine = OHIF.viewer.cine;
|
const cine = OHIF.viewer.cine;
|
||||||
@ -99,7 +105,10 @@ Template.cineDialog.onCreated(() => {
|
|||||||
cine.loop = _.isUndefined(cine.loop) ? true : cine.loop;
|
cine.loop = _.isUndefined(cine.loop) ? true : cine.loop;
|
||||||
|
|
||||||
// Set the updated data on the form inputs
|
// 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
|
// Update the session to refresh the framerate text
|
||||||
Session.set('UpdateCINE', Random.id());
|
Session.set('UpdateCINE', Random.id());
|
||||||
@ -204,11 +213,9 @@ Template.cineDialog.onCreated(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Template.cineDialog.onRendered(() => {
|
Template.cineDialog.onRendered(() => {
|
||||||
|
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
const dialog = instance.$('#cineDialog');
|
||||||
let dialog = instance.$('#cineDialog'),
|
const singleRowLayout = OHIF.uiSettings.displayEchoUltrasoundWorkflow;
|
||||||
singleRowLayout = OHIF.uiSettings.displayEchoUltrasoundWorkflow;
|
|
||||||
|
|
||||||
// set dialog in optimal position and make sure it continues in a optimal position...
|
// set dialog in optimal position and make sure it continues in a optimal position...
|
||||||
// ... when the window has been resized
|
// ... when the window has been resized
|
||||||
@ -222,7 +229,10 @@ Template.cineDialog.onRendered(() => {
|
|||||||
instance.setResizeHandler(instance.setOptimalPosition);
|
instance.setResizeHandler(instance.setOptimalPosition);
|
||||||
|
|
||||||
// Make the CINE dialog bounded and draggable
|
// 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
|
// Prevent dialog from being dragged when user clicks any button
|
||||||
dialog.find('.cine-navigation, .cine-controls, .cine-options').on('mousedown touchstart', function (e) {
|
dialog.find('.cine-navigation, .cine-controls, .cine-options').on('mousedown touchstart', function (e) {
|
||||||
@ -239,7 +249,7 @@ Template.cineDialog.onDestroyed(() => {
|
|||||||
|
|
||||||
Template.cineDialog.events({
|
Template.cineDialog.events({
|
||||||
'change [data-key=loop] input'(event, instance) {
|
'change [data-key=loop] input'(event, instance) {
|
||||||
const element = getActiveViewportElement();
|
const element = viewportUtils.getActiveViewportElement();
|
||||||
const playClipToolData = cornerstoneTools.getToolState(element, 'playClip');
|
const playClipToolData = cornerstoneTools.getToolState(element, 'playClip');
|
||||||
playClipToolData.data[0].loop = $(event.currentTarget).is(':checked');
|
playClipToolData.data[0].loop = $(event.currentTarget).is(':checked');
|
||||||
OHIF.viewer.cine.loop = playClipToolData.data[0].loop;
|
OHIF.viewer.cine.loop = playClipToolData.data[0].loop;
|
||||||
@ -254,7 +264,7 @@ Template.cineDialog.events({
|
|||||||
|
|
||||||
Template.cineDialog.helpers({
|
Template.cineDialog.helpers({
|
||||||
isPlaying() {
|
isPlaying() {
|
||||||
return isPlaying();
|
return viewportUtils.isPlaying();
|
||||||
},
|
},
|
||||||
|
|
||||||
framerate() {
|
framerate() {
|
||||||
@ -264,11 +274,11 @@ Template.cineDialog.helpers({
|
|||||||
|
|
||||||
displaySetDisabled(isNext) {
|
displaySetDisabled(isNext) {
|
||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
return !OHIF.viewer.canMoveDisplaySets(isNext) ? 'disabled' : '';
|
return !OHIF.viewerbase.layoutManager.canMoveDisplaySets(isNext) ? 'disabled' : '';
|
||||||
},
|
},
|
||||||
|
|
||||||
buttonDisabled() {
|
buttonDisabled() {
|
||||||
return hasMultipleFrames();
|
return viewportUtils.hasMultipleFrames();
|
||||||
},
|
},
|
||||||
|
|
||||||
getClassNames(baseCls) {
|
getClassNames(baseCls) {
|
||||||
|
|||||||
@ -1,69 +1,26 @@
|
|||||||
function closeHandler() {
|
import { Template } from 'meteor/templating';
|
||||||
// Hide the lesion dialog
|
|
||||||
$('#confirmDeleteDialog').css('display', 'none');
|
|
||||||
|
|
||||||
// Remove the backdrop
|
import { dialogUtils } from '../../../lib/dialogUtils';
|
||||||
$('.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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Global object of key names (TODO: put this somewhere else)
|
// Global object of key names (TODO: put this somewhere else)
|
||||||
keys = {
|
const keys = {
|
||||||
ESC: 27,
|
ESC: 27,
|
||||||
ENTER: 13
|
ENTER: 13
|
||||||
};
|
};
|
||||||
|
|
||||||
Template.confirmDeleteDialog.events({
|
Template.confirmDeleteDialog.events({
|
||||||
'click #cancel, click #close': function() {
|
'click #cancel, click #close'() {
|
||||||
closeHandler();
|
// Action canceled, just close dialog without calling callback
|
||||||
|
dialogUtils.closeHandler(false);
|
||||||
},
|
},
|
||||||
'click #confirm': function() {
|
'click #confirm'() {
|
||||||
var doneCallback = Template.confirmDeleteDialog.doneCallback;
|
// Action confirmed, close dialog and calls callback, if exists
|
||||||
if (doneCallback && typeof doneCallback === 'function') {
|
dialogUtils.closeHandler();
|
||||||
doneCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
closeHandler();
|
|
||||||
},
|
},
|
||||||
'keydown #confirmDeleteDialog': function(e) {
|
'keydown #confirmDeleteDialog'(e) {
|
||||||
|
// Action canceled, just close dialog without calling callback
|
||||||
if (e.which === keys.ESC) {
|
if (e.which === keys.ESC) {
|
||||||
closeHandler();
|
dialogUtils.closeHandler(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,15 +28,10 @@ Template.confirmDeleteDialog.events({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var doneCallback = Template.confirmDeleteDialog.doneCallback;
|
// If Enter is pressed
|
||||||
|
|
||||||
// If Enter is pressed, close the dialog
|
|
||||||
if (e.which === keys.ENTER) {
|
if (e.which === keys.ENTER) {
|
||||||
if (doneCallback && typeof doneCallback === 'function') {
|
// Action confirmed, close dialog and calls callback, if exists
|
||||||
doneCallback();
|
dialogUtils.closeHandler();
|
||||||
}
|
|
||||||
|
|
||||||
closeHandler();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,13 +15,13 @@ Template.displaySetNavigation.events({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OHIF.viewer.moveDisplaySets(false);
|
OHIF.viewerbase.layoutManager.moveDisplaySets(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.displaySetNavigation.helpers({
|
Template.displaySetNavigation.helpers({
|
||||||
disableButton(isNext) {
|
disableButton(isNext) {
|
||||||
Session.get('LayoutManagerUpdated');
|
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;
|
const slideTimeoutTime = 40;
|
||||||
let slideTimeout;
|
let slideTimeout;
|
||||||
|
|
||||||
@ -33,7 +38,7 @@ Template.imageControls.events({
|
|||||||
OHIF.viewer.hotkeyFunctions.scrollUp();
|
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
|
// Note that we throttle requests to prevent the
|
||||||
// user's ultrafast scrolling from firing requests too quickly.
|
// user's ultrafast scrolling from firing requests too quickly.
|
||||||
clearTimeout(slideTimeout);
|
clearTimeout(slideTimeout);
|
||||||
@ -41,7 +46,7 @@ Template.imageControls.events({
|
|||||||
// Using the slider in an inactive viewport
|
// Using the slider in an inactive viewport
|
||||||
// should cause that viewport to become active
|
// should cause that viewport to become active
|
||||||
const slider = $(event.currentTarget);
|
const slider = $(event.currentTarget);
|
||||||
const newActiveElement = slider.parents().eq(2).siblings('.imageViewerViewport').get(0);
|
const newActiveElement = slider.parents('.viewportContainer').find('.imageViewerViewport');
|
||||||
setActiveViewport(newActiveElement);
|
setActiveViewport(newActiveElement);
|
||||||
|
|
||||||
// Subtract 1 here since the slider goes from 1 to N images
|
// 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({
|
Template.layoutButton.events({
|
||||||
// TODO: Check why 'click' event won't fire?
|
// TODO: Check why 'click' event won't fire?
|
||||||
'mousedown .js-dropdown-toggle'(event) {
|
'mousedown .js-dropdown-toggle'(event) {
|
||||||
@ -12,6 +16,6 @@ Template.layoutButton.events({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Open or close the layout chooser dialog
|
// 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(() => {
|
Template.layoutChooser.onRendered(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|
||||||
@ -35,12 +41,12 @@ Template.layoutChooser.onRendered(() => {
|
|||||||
// Refresh layout chooser highlighting based on current viewports state
|
// Refresh layout chooser highlighting based on current viewports state
|
||||||
instance.refreshHighlights = () => {
|
instance.refreshHighlights = () => {
|
||||||
// Stop here if layoutManager is not defined yet
|
// Stop here if layoutManager is not defined yet
|
||||||
if (!window.layoutManager) {
|
if (!OHIF.viewerbase.layoutManager) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the layout rows and columns amount
|
// Get the layout rows and columns amount
|
||||||
const info = window.layoutManager.layoutProps;
|
const info = OHIF.viewerbase.layoutManager.layoutProps;
|
||||||
|
|
||||||
// get the limiter cell
|
// get the limiter cell
|
||||||
const cell = instance.$('tr').eq(info.rows - 1).children().eq(info.columns - 1);
|
const cell = instance.$('tr').eq(info.rows - 1).children().eq(info.columns - 1);
|
||||||
@ -77,11 +83,11 @@ Template.layoutChooser.events({
|
|||||||
columns: columnIndex + 1
|
columns: columnIndex + 1
|
||||||
};
|
};
|
||||||
|
|
||||||
window.layoutManager.layoutTemplateName = 'gridLayout';
|
OHIF.viewerbase.layoutManager.layoutTemplateName = 'gridLayout';
|
||||||
window.layoutManager.layoutProps = layoutProps;
|
OHIF.viewerbase.layoutManager.layoutProps = layoutProps;
|
||||||
window.layoutManager.updateViewports();
|
OHIF.viewerbase.layoutManager.updateViewports();
|
||||||
|
|
||||||
const $dropdown = instance.$('.layoutChooser');
|
const $dropdown = instance.$('.layoutChooser');
|
||||||
toggleDialog($dropdown);
|
viewportUtils.toggleDialog($dropdown);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
Meteor.startup(function() {
|
Meteor.startup(function() {
|
||||||
@ -8,43 +11,41 @@ Meteor.startup(function() {
|
|||||||
|
|
||||||
var loadHandlerTimeout;
|
var loadHandlerTimeout;
|
||||||
|
|
||||||
startLoadingHandler = function(element) {
|
const startLoadingHandler = function(element) {
|
||||||
clearTimeout(loadHandlerTimeout);
|
clearTimeout(loadHandlerTimeout);
|
||||||
loadHandlerTimeout = setTimeout(function() {
|
loadHandlerTimeout = setTimeout(function() {
|
||||||
console.log('startLoading');
|
console.log('startLoading');
|
||||||
var elem = $(element);
|
var elem = $(element);
|
||||||
elem.siblings('.imageViewerErrorLoadingIndicator').css('display', 'none');
|
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');
|
elem.siblings('.imageViewerLoadingIndicator').css('display', 'block');
|
||||||
}, OHIF.viewer.loadIndicatorDelay);
|
}, OHIF.viewer.loadIndicatorDelay);
|
||||||
};
|
};
|
||||||
|
|
||||||
doneLoadingHandler = function(element) {
|
const doneLoadingHandler = function(element) {
|
||||||
clearTimeout(loadHandlerTimeout);
|
clearTimeout(loadHandlerTimeout);
|
||||||
var elem = $(element);
|
var elem = $(element);
|
||||||
elem.siblings('.imageViewerErrorLoadingIndicator').css('display', 'none');
|
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');
|
elem.siblings('.imageViewerLoadingIndicator').css('display', 'none');
|
||||||
};
|
};
|
||||||
|
|
||||||
errorLoadingHandler = function(element, imageId, error, source) {
|
const errorLoadingHandler = function(element, imageId, error, source) {
|
||||||
clearTimeout(loadHandlerTimeout);
|
clearTimeout(loadHandlerTimeout);
|
||||||
var elem = $(element);
|
var elem = $(element);
|
||||||
|
|
||||||
// Could probably chain all of these, but this is more readable
|
// 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');
|
elem.siblings('.imageViewerLoadingIndicator').css('display', 'none');
|
||||||
|
|
||||||
// Don't display errors from the stackPrefetch tool
|
// Don't display errors from the stackPrefetch tool
|
||||||
if (source === "stackPrefetch") {
|
if (source === 'stackPrefetch') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var errorLoadingIndicator = elem.siblings('.imageViewerErrorLoadingIndicator');
|
var errorLoadingIndicator = elem.siblings('.imageViewerErrorLoadingIndicator');
|
||||||
errorLoadingIndicator.css('display', 'block');
|
errorLoadingIndicator.css('display', 'block');
|
||||||
|
|
||||||
var cleanedImageId = imageId;
|
|
||||||
|
|
||||||
// This is just used to expand upon some error messages that are sent
|
// 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
|
// when things fail. An example is a network error throwing the error
|
||||||
// which is only described as "network".
|
// which is only described as "network".
|
||||||
@ -57,7 +58,7 @@ errorLoadingHandler = function(element, imageId, error, source) {
|
|||||||
error = errorDetails[error];
|
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) {
|
if (error) {
|
||||||
errorLoadingIndicator.find('.details').text("Details: " + error);
|
errorLoadingIndicator.find('.details').text("Details: " + error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { viewportUtils } from '../../../lib/viewportUtils';
|
||||||
|
|
||||||
Template.playClipButton.helpers({
|
Template.playClipButton.helpers({
|
||||||
isPlaying: function() {
|
isPlaying: function() {
|
||||||
return isPlaying();
|
return viewportUtils.isPlaying();
|
||||||
},
|
},
|
||||||
disableButton() {
|
disableButton() {
|
||||||
return hasMultipleFrames();
|
return viewportUtils.hasMultipleFrames();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { ReactiveVar } from 'meteor/reactive-var';
|
import { ReactiveVar } from 'meteor/reactive-var';
|
||||||
import { Session } from 'meteor/session';
|
import { Session } from 'meteor/session';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
|
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import 'meteor/ohif:viewerbase';
|
||||||
|
|
||||||
Template.studySeriesQuickSwitch.onCreated(() => {
|
Template.studySeriesQuickSwitch.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
@ -10,7 +14,7 @@ Template.studySeriesQuickSwitch.onCreated(() => {
|
|||||||
|
|
||||||
// Gets the viewport data for the given viewport index
|
// Gets the viewport data for the given viewport index
|
||||||
instance.getViewportData = viewportIndex => {
|
instance.getViewportData = viewportIndex => {
|
||||||
const layoutManager = window.layoutManager;
|
const layoutManager = OHIF.viewerbase.layoutManager;
|
||||||
return layoutManager && layoutManager.viewportData && layoutManager.viewportData[viewportIndex];
|
return layoutManager && layoutManager.viewportData && layoutManager.viewportData[viewportIndex];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { ReactiveVar } from 'meteor/reactive-var';
|
|||||||
import { Tracker } from 'meteor/tracker';
|
import { Tracker } from 'meteor/tracker';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
|
import { OHIFError } from '../../../lib/classes/OHIFError';
|
||||||
|
|
||||||
Template.studyTimepointBrowser.onCreated(() => {
|
Template.studyTimepointBrowser.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ Template.studyTimepointBrowser.onCreated(() => {
|
|||||||
|
|
||||||
const notYetLoaded = StudyListStudies.findOne(query);
|
const notYetLoaded = StudyListStudies.findOne(query);
|
||||||
if (!notYetLoaded) {
|
if (!notYetLoaded) {
|
||||||
throw 'No study data available for Study: ' + studyInstanceUid;
|
throw new OHIFError(`No study data available for Study: ${studyInstanceUid}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return notYetLoaded;
|
return notYetLoaded;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { Template } from 'meteor/templating';
|
|||||||
import { ReactiveVar } from 'meteor/reactive-var';
|
import { ReactiveVar } from 'meteor/reactive-var';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
import { $ } from 'meteor/jquery';
|
import { $ } from 'meteor/jquery';
|
||||||
|
import { sortingManager } from '../../../lib/sortingManager';
|
||||||
|
|
||||||
Template.studyTimepointStudy.onCreated(() => {
|
Template.studyTimepointStudy.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
@ -16,11 +17,6 @@ Template.studyTimepointStudy.onCreated(() => {
|
|||||||
return isGlobal ? $(selector) : instance.$browser.find(selector);
|
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
|
// Set the current study as selected in the studies list
|
||||||
instance.select = (isQuickSwitch=false) => {
|
instance.select = (isQuickSwitch=false) => {
|
||||||
const studyInstanceUid = instance.data.study.studyInstanceUid;
|
const studyInstanceUid = instance.data.study.studyInstanceUid;
|
||||||
@ -110,7 +106,7 @@ Template.studyTimepointStudy.events({
|
|||||||
const $studies = instance.getStudyElement(true);
|
const $studies = instance.getStudyElement(true);
|
||||||
$studies.trigger('loadStarted');
|
$studies.trigger('loadStarted');
|
||||||
getStudyMetadata(studyInstanceUid, study => {
|
getStudyMetadata(studyInstanceUid, study => {
|
||||||
study.displaySets = createStacks(study);
|
study.displaySets = sortingManager.getDisplaySets(study);
|
||||||
instance.data.study = study;
|
instance.data.study = study;
|
||||||
ViewerStudies.insert(study, () => {
|
ViewerStudies.insert(study, () => {
|
||||||
// To make sure studies are rendered in the DOM
|
// To make sure studies are rendered in the DOM
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { OHIF } from 'meteor/ohif:core';
|
|||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { Session } from 'meteor/session';
|
import { Session } from 'meteor/session';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
|
import { toolManager } from '../../../lib/toolManager';
|
||||||
|
|
||||||
Template.toolbarSectionButton.onCreated(() => {
|
Template.toolbarSectionButton.onCreated(() => {
|
||||||
const instance = Template.instance();
|
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 { 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(() => {
|
Template.viewerMain.onCreated(() => {
|
||||||
// Attach the Window resize listener
|
// Attach the Window resize listener
|
||||||
@ -8,23 +23,22 @@ Template.viewerMain.onCreated(() => {
|
|||||||
// and change it to jQuery._data(window, 'events')['resize'].
|
// and change it to jQuery._data(window, 'events')['resize'].
|
||||||
// Otherwise this function will be probably overrided.
|
// Otherwise this function will be probably overrided.
|
||||||
// See cineDialog instance.setResizeHandler function
|
// 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
|
// Add beforeUnload event handler to check for unsaved changes
|
||||||
window.addEventListener('beforeunload', unloadHandlers.beforeUnload);
|
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(() => {
|
Template.viewerMain.onRendered(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|
||||||
HP.ProtocolStore.onReady(() => {
|
instance.subscribe('hangingprotocols', () => {
|
||||||
const { studies, currentTimepointId, measurementApi, timepointIds } = instance.data;
|
const { studies, currentTimepointId, measurementApi, timepointIds } = instance.data;
|
||||||
const parentElement = instance.$('#layoutManagerTarget').get(0);
|
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
|
// Default actions for Associated Studies
|
||||||
if(currentTimepointId) {
|
if(currentTimepointId) {
|
||||||
// Follow-up studies: same as the first measurement in the table
|
// Follow-up studies: same as the first measurement in the table
|
||||||
@ -73,18 +87,22 @@ Template.viewerMain.onRendered(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Toggle Measurement Table
|
// 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
|
// Hide as default for single study
|
||||||
else {
|
else {
|
||||||
instance.data.state.set('rightSidebar', null);
|
if(instance.data.state) {
|
||||||
|
instance.data.state.set('rightSidebar', null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolEngine = new HP.ProtocolEngine(window.layoutManager, studies);
|
// ProtocolEngine = new HP.ProtocolEngine(OHIF.viewerbase.layoutManager, studies);
|
||||||
HP.setEngine(ProtocolEngine);
|
// HP.setEngine(ProtocolEngine);
|
||||||
|
|
||||||
// Enable hotkeys
|
// Enable hotkeys
|
||||||
enableHotkeys();
|
hotkeyUtils.enableHotkeys();
|
||||||
|
|
||||||
Session.set('ViewerMainReady', Random.id());
|
Session.set('ViewerMainReady', Random.id());
|
||||||
});
|
});
|
||||||
@ -94,7 +112,7 @@ Template.viewerMain.onDestroyed(() => {
|
|||||||
OHIF.log.info('viewerMain onDestroyed');
|
OHIF.log.info('viewerMain onDestroyed');
|
||||||
|
|
||||||
// Remove the Window resize listener
|
// Remove the Window resize listener
|
||||||
window.removeEventListener('resize', handleResize);
|
window.removeEventListener('resize', window.ResizeViewportManager.handleResize.bind(window.ResizeViewportManager));
|
||||||
|
|
||||||
// Remove beforeUnload event handler...
|
// Remove beforeUnload event handler...
|
||||||
window.removeEventListener('beforeunload', unloadHandlers.beforeUnload);
|
window.removeEventListener('beforeunload', unloadHandlers.beforeUnload);
|
||||||
@ -102,6 +120,6 @@ Template.viewerMain.onDestroyed(() => {
|
|||||||
// Destroy the synchronizer used to update reference lines
|
// Destroy the synchronizer used to update reference lines
|
||||||
OHIF.viewer.updateImageSynchronizer.destroy();
|
OHIF.viewer.updateImageSynchronizer.destroy();
|
||||||
|
|
||||||
delete window.layoutManager;
|
delete OHIF.viewerbase.layoutManager;
|
||||||
delete ProtocolEngine;
|
delete ProtocolEngine;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,253 +1,147 @@
|
|||||||
function getElementIfNotEmpty(viewportIndex) {
|
import { Template } from 'meteor/templating';
|
||||||
// Meteor template helpers run more often than expected
|
import { Session } from 'meteor/session';
|
||||||
// They often seem to run just before the whole template is rendered
|
import { viewportOverlayUtils } from '../../../lib/viewportOverlayUtils';
|
||||||
// This meant that the onRendered event hadn't fired yet, so the
|
import { getElementIfNotEmpty } from '../../../lib/getElementIfNotEmpty';
|
||||||
// element wasn't enabled / set empty yet. The check here
|
import { getStackDataIfNotEmpty } from '../../../lib/getStackDataIfNotEmpty';
|
||||||
// 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}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
Template.viewportOverlay.helpers({
|
Template.viewportOverlay.helpers({
|
||||||
wwwc: function() {
|
wwwc() {
|
||||||
Session.get('CornerstoneImageRendered' + this.viewportIndex);
|
Session.get('CornerstoneImageRendered' + this.viewportIndex);
|
||||||
var element = getElementIfNotEmpty(this.viewportIndex);
|
|
||||||
|
const element = getElementIfNotEmpty(this.viewportIndex);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewport = cornerstone.getViewport(element);
|
const viewport = cornerstone.getViewport(element);
|
||||||
if (!viewport) {
|
if (!viewport) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'W ' + viewport.voi.windowWidth.toFixed(0) + ' L ' + viewport.voi.windowCenter.toFixed(0);
|
return 'W ' + viewport.voi.windowWidth.toFixed(0) + ' L ' + viewport.voi.windowCenter.toFixed(0);
|
||||||
},
|
},
|
||||||
zoom: function() {
|
zoom() {
|
||||||
Session.get('CornerstoneImageRendered' + this.viewportIndex);
|
Session.get('CornerstoneImageRendered' + this.viewportIndex);
|
||||||
var element = getElementIfNotEmpty(this.viewportIndex);
|
|
||||||
|
const element = getElementIfNotEmpty(this.viewportIndex);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewport = cornerstone.getViewport(element);
|
const viewport = cornerstone.getViewport(element);
|
||||||
if (!viewport) {
|
if (!viewport) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (viewport.scale * 100.0);
|
return (viewport.scale * 100.0);
|
||||||
},
|
},
|
||||||
imageDimensions: function() {
|
imageDimensions() {
|
||||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
var image = getImage(this.viewportIndex);
|
const image = viewportOverlayUtils.getImage(this.viewportIndex);
|
||||||
if (!image) {
|
if (!image) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return image.width + ' x ' + image.height;
|
return image.width + ' x ' + image.height;
|
||||||
},
|
},
|
||||||
patientName: function() {
|
patientName() {
|
||||||
return getPatient.call(this, 'name');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getPatient.call(this, 'name');
|
||||||
},
|
},
|
||||||
patientId: function() {
|
patientId() {
|
||||||
return getPatient.call(this, 'id');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getPatient.call(this, 'id');
|
||||||
},
|
},
|
||||||
patientBirthDate: function() {
|
patientBirthDate() {
|
||||||
return getPatient.call(this, 'birthDate');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getPatient.call(this, 'birthDate');
|
||||||
},
|
},
|
||||||
patientSex: function() {
|
patientSex() {
|
||||||
return getPatient.call(this, 'sex');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getPatient.call(this, 'sex');
|
||||||
},
|
},
|
||||||
studyDate: function() {
|
studyDate() {
|
||||||
return getStudy.call(this, 'studyDate');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getStudy.call(this, 'studyDate');
|
||||||
},
|
},
|
||||||
studyTime: function() {
|
studyTime() {
|
||||||
return getStudy.call(this, 'studyTime');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getStudy.call(this, 'studyTime');
|
||||||
},
|
},
|
||||||
studyDescription: function() {
|
studyDescription() {
|
||||||
return getStudy.call(this, 'studyDescription');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getStudy.call(this, 'studyDescription');
|
||||||
},
|
},
|
||||||
seriesDescription: function() {
|
seriesDescription() {
|
||||||
return getSeries.call(this, 'seriesDescription');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getSeries.call(this, 'seriesDescription');
|
||||||
},
|
},
|
||||||
frameRate: function() {
|
frameRate() {
|
||||||
var frameTime = getInstance.call(this, 'frameTime');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
const frameTime = viewportOverlayUtils.getInstance.call(this, 'frameTime');
|
||||||
if (!frameTime) {
|
if (!frameTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var frameRate = 1000 / frameTime;
|
const frameRate = 1000 / frameTime;
|
||||||
return frameRate.toFixed(1);
|
return frameRate.toFixed(1);
|
||||||
},
|
},
|
||||||
seriesNumber: function() {
|
seriesNumber() {
|
||||||
return getSeries.call(this, 'seriesNumber');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getSeries.call(this, 'seriesNumber');
|
||||||
},
|
},
|
||||||
instanceNumber: function() {
|
instanceNumber() {
|
||||||
return getInstance.call(this, 'instanceNumber');
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getInstance.call(this, 'instanceNumber');
|
||||||
},
|
},
|
||||||
thickness() {
|
thickness() {
|
||||||
// Displays Slice Thickness (0018,0050)
|
// Displays Slice Thickness (0018,0050)
|
||||||
return getInstance.call(this, 'sliceThickness');
|
|
||||||
},
|
|
||||||
|
|
||||||
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getInstance.call(this, 'sliceThickness');
|
||||||
|
},
|
||||||
location() {
|
location() {
|
||||||
// Displays Slice Location (0020,1041), if present.
|
// Displays Slice Location (0020,1041), if present.
|
||||||
// - Otherwise, displays Table Position (0018,9327)
|
// - Otherwise, displays Table Position (0018,9327)
|
||||||
// - TODO: Otherwise, displays a value derived from Image Position (Patient) (0020,0032)
|
// - 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 !== '') {
|
if (sliceLocation !== '') {
|
||||||
return sliceLocation;
|
return sliceLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tablePosition = getInstance.call(this, 'tablePosition');
|
const tablePosition = viewportOverlayUtils.getInstance.call(this, 'tablePosition');
|
||||||
if (tablePosition !== '') {
|
if (tablePosition !== '') {
|
||||||
return tablePosition;
|
return tablePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getInstance.call(this, 'imagePositionPatient');
|
return viewportOverlayUtils.getInstance.call(this, 'imagePositionPatient');
|
||||||
},
|
},
|
||||||
|
|
||||||
spacingBetweenSlices() {
|
spacingBetweenSlices() {
|
||||||
// Displays Spacing Between Slices (0018,0088), if present.
|
// Displays Spacing Between Slices (0018,0088), if present.
|
||||||
|
|
||||||
// TODO: Otherwise, displays a value derived from successive values
|
// TODO: Otherwise, displays a value derived from successive values
|
||||||
// of Image Position (Patient) (0020,0032) perpendicular to
|
// of Image Position (Patient) (0020,0032) perpendicular to
|
||||||
// the Image Orientation (Patient) (0020,0037)
|
// the Image Orientation (Patient) (0020,0037)
|
||||||
return getInstance.call(this, 'spacingBetweenSlices');
|
|
||||||
},
|
|
||||||
|
|
||||||
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
|
return viewportOverlayUtils.getInstance.call(this, 'spacingBetweenSlices');
|
||||||
|
},
|
||||||
compression() {
|
compression() {
|
||||||
// Displays whether or not lossy compression has been applied:
|
// Displays whether or not lossy compression has been applied:
|
||||||
//
|
//
|
||||||
@ -256,11 +150,12 @@ Template.viewportOverlay.helpers({
|
|||||||
// and Lossy Image Compression Method (0028,2114)
|
// and Lossy Image Compression Method (0028,2114)
|
||||||
|
|
||||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
if (!this.imageId) {
|
if (!this.imageId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance = cornerstoneTools.metaData.get('instance', this.imageId);
|
const instance = cornerstoneTools.metaData.get('instance', this.imageId);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@ -274,43 +169,56 @@ Template.viewportOverlay.helpers({
|
|||||||
|
|
||||||
return 'Lossless / Uncompressed';
|
return 'Lossless / Uncompressed';
|
||||||
},
|
},
|
||||||
|
tagDisplayLeftOnly() {
|
||||||
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() {
|
|
||||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
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) {
|
if (!stack || stack.currentImageIdIndex === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stack.currentImageIdIndex + 1;
|
return stack.currentImageIdIndex + 1;
|
||||||
},
|
},
|
||||||
numImages: function() {
|
numImages() {
|
||||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
var stack = getStackDataIfNotEmpty(this.viewportIndex);
|
|
||||||
|
const stack = getStackDataIfNotEmpty(this.viewportIndex);
|
||||||
if (!stack || !stack.imageIds) {
|
if (!stack || !stack.imageIds) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stack.imageIds.length;
|
return stack.imageIds.length;
|
||||||
},
|
},
|
||||||
prior: function() {
|
prior() {
|
||||||
// This helper is updated whenever a new image is displayed in the viewport
|
// This helper is updated whenever a new image is displayed in the viewport
|
||||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||||
|
|
||||||
if (!this.imageId) {
|
if (!this.imageId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there are more than two studies loaded in the viewer
|
// Make sure there are more than two studies loaded in the viewer
|
||||||
var viewportStudies = ViewerStudies.find();
|
const viewportStudies = ViewerStudies.find();
|
||||||
if (viewportStudies.count() < 2) {
|
if (viewportStudies.count() < 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -319,18 +227,18 @@ Template.viewportOverlay.helpers({
|
|||||||
// that we can obtain the oldest study as the first element of the array
|
// 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
|
// TODO= Find out if we should encode studyDate as a Date in the ViewerStudies Collection
|
||||||
var viewportStudiesArray = _.sortBy(viewportStudies.fetch(), function(study) {
|
const viewportStudiesArray = _.sortBy(viewportStudies.fetch(), function(study) {
|
||||||
return formatDateTime(study.studyDate, study.studyTime);
|
return viewportOverlayUtils.formatDateTime(study.studyDate, study.studyTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get study data
|
// Get study data
|
||||||
var study = cornerstoneTools.metaData.get('study', this.imageId);
|
const study = cornerstoneTools.metaData.get('study', this.imageId);
|
||||||
if (!study) {
|
if (!study) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldestStudy = viewportStudiesArray[0];
|
const oldestStudy = viewportStudiesArray[0];
|
||||||
if (formatDateTime(study.studyDate, study.studyTime) <= formatDateTime(oldestStudy.studyDate, oldestStudy.studyTime)) {
|
if (viewportOverlayUtils.formatDateTime(study.studyDate, study.studyTime) <= viewportOverlayUtils.formatDateTime(oldestStudy.studyDate, oldestStudy.studyTime)) {
|
||||||
return 'Prior';
|
return 'Prior';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -185,7 +185,8 @@ import { OHIFError } from './lib/classes/OHIFError';
|
|||||||
Viewerbase.OHIFError = OHIFError;
|
Viewerbase.OHIFError = OHIFError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports for Side Effects Only
|
* Imports for Side Effects Only (Files that do not export anything...)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import './lib/stackImagePositionOffsetSynchronizer.js';
|
||||||
import './lib/debugReactivity';
|
import './lib/debugReactivity';
|
||||||
|
|||||||
@ -1,28 +1,86 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import { viewportUtils } from './viewportUtils';
|
||||||
|
|
||||||
applyWLPreset = function(presetName, element) {
|
// TODO: add this to a namespace definition
|
||||||
OHIF.log.info("Applying WL Preset: " + presetName);
|
Meteor.startup(function() {
|
||||||
var viewport = cornerstone.getViewport(element);
|
OHIF.viewer.defaultWLPresets = {
|
||||||
|
SoftTissue: {
|
||||||
|
wc: 40,
|
||||||
|
ww: 400
|
||||||
|
},
|
||||||
|
Lung: {
|
||||||
|
wc: -600,
|
||||||
|
ww: 1500
|
||||||
|
},
|
||||||
|
Liver: {
|
||||||
|
wc: 90,
|
||||||
|
ww: 150
|
||||||
|
},
|
||||||
|
Bone: {
|
||||||
|
wc: 480,
|
||||||
|
ww: 2500
|
||||||
|
},
|
||||||
|
Brain: {
|
||||||
|
wc: 40,
|
||||||
|
ww: 80
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (presetName === 'Default') {
|
// For now
|
||||||
var enabledElement = cornerstone.getEnabledElement(element);
|
OHIF.viewer.wlPresets = OHIF.viewer.defaultWLPresets;
|
||||||
viewport.voi.windowWidth = enabledElement.image.windowWidth;
|
});
|
||||||
viewport.voi.windowCenter = enabledElement.image.windowCenter;
|
|
||||||
} else {
|
function applyWLPreset(presetName, element) {
|
||||||
var preset = OHIF.viewer.wlPresets[presetName];
|
OHIF.log.info('Applying WL Preset: ' + presetName);
|
||||||
viewport.voi.windowWidth = preset.ww;
|
if (presetName !== 'Custom') {
|
||||||
viewport.voi.windowCenter = preset.wc;
|
const viewport = cornerstone.getViewport(element);
|
||||||
|
|
||||||
|
if (presetName === 'Default') {
|
||||||
|
const enabledElement = cornerstone.getEnabledElement(element);
|
||||||
|
viewport.voi.windowWidth = enabledElement.image.windowWidth;
|
||||||
|
viewport.voi.windowCenter = enabledElement.image.windowCenter;
|
||||||
|
} else {
|
||||||
|
const preset = OHIF.viewer.wlPresets[presetName];
|
||||||
|
if(preset) {
|
||||||
|
viewport.voi.windowWidth = preset.ww;
|
||||||
|
viewport.voi.windowCenter = preset.wc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the viewport
|
||||||
|
cornerstone.setViewport(element, viewport);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update the viewport
|
function applyWLPresetToActiveElement(presetName) {
|
||||||
cornerstone.setViewport(element, viewport);
|
const element = viewportUtils.getActiveViewportElement();
|
||||||
};
|
|
||||||
|
|
||||||
applyWLPresetToActiveElement = function(presetName) {
|
|
||||||
var element = getActiveViewportElement();
|
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyWLPreset(presetName, element);
|
applyWLPreset(presetName, element);
|
||||||
|
|
||||||
|
// To perform reactivity in other components
|
||||||
|
Session.set('WLPresetActiveElement', presetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides OHIF's wlPresets
|
||||||
|
* @param {Object} wlPresets Object with wlPresets mapping
|
||||||
|
*/
|
||||||
|
function setOHIFWLPresets(wlPresets) {
|
||||||
|
OHIF.viewer.wlPresets = wlPresets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export functions inside WLPresets namespace.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const WLPresets = {
|
||||||
|
applyWLPreset,
|
||||||
|
applyWLPresetToActiveElement,
|
||||||
|
setOHIFWLPresets
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { WLPresets };
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import { ImageSet } from './classes/ImageSet';
|
||||||
|
import { isImage } from './isImage';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a set of series to be placed in the Study Browser
|
* Creates a set of series to be placed in the Study Browser
|
||||||
* The series that appear in the Study Browser must represent
|
* The series that appear in the Study Browser must represent
|
||||||
@ -10,7 +13,7 @@
|
|||||||
* @param study The study instance to be used
|
* @param study The study instance to be used
|
||||||
* @returns {Array} An array of series to be placed in the Study Browser
|
* @returns {Array} An array of series to be placed in the Study Browser
|
||||||
*/
|
*/
|
||||||
createStacks = function(study) {
|
function createStacks(study) {
|
||||||
// Define an empty array of display sets
|
// Define an empty array of display sets
|
||||||
var displaySets = [];
|
var displaySets = [];
|
||||||
|
|
||||||
@ -38,33 +41,21 @@ createStacks = function(study) {
|
|||||||
let displaySet;
|
let displaySet;
|
||||||
if (isMultiFrame(instance)) {
|
if (isMultiFrame(instance)) {
|
||||||
displaySet = makeDisplaySet(series, [ instance ]);
|
displaySet = makeDisplaySet(series, [ instance ]);
|
||||||
displaySet.isClip = true;
|
displaySet.setAttributes({
|
||||||
|
isClip: true,
|
||||||
// Include the study instance Uid for drag/drop purposes
|
studyInstanceUid: study.studyInstanceUid, // Include the study instance Uid for drag/drop purposes
|
||||||
displaySet.studyInstanceUid = study.studyInstanceUid;
|
numImageFrames: instance.numFrames, // Override the default value of instances.length
|
||||||
|
instanceNumber: instance.instanceNumber, // Include the instance number
|
||||||
// Override the default value of instances.length
|
acquisitionDatetime: instance.acquisitionDatetime // Include the acquisition datetime
|
||||||
displaySet.numImageFrames = instance.numFrames;
|
});
|
||||||
|
|
||||||
// Include the instance number
|
|
||||||
displaySet.instanceNumber = instance.instanceNumber;
|
|
||||||
|
|
||||||
// Include the acquisition datetime
|
|
||||||
displaySet.acquisitionDatetime = instance.acquisitionDatetime;
|
|
||||||
|
|
||||||
displaySets.push(displaySet);
|
displaySets.push(displaySet);
|
||||||
} else if (isSingleImageModality(instance.modality)) {
|
} else if (isSingleImageModality(instance.modality)) {
|
||||||
displaySet = makeDisplaySet(series, [ instance ]);
|
displaySet = makeDisplaySet(series, [ instance ]);
|
||||||
|
displaySet.setAttributes({
|
||||||
// Include the study instance Uid
|
studyInstanceUid: study.studyInstanceUid, // Include the study instance Uid
|
||||||
displaySet.studyInstanceUid = study.studyInstanceUid;
|
instanceNumber: instance.instanceNumber, // Include the instance number
|
||||||
|
acquisitionDatetime: instance.acquisitionDatetime // Include the acquisition datetime
|
||||||
// Include the instance number
|
});
|
||||||
displaySet.instanceNumber = instance.instanceNumber;
|
|
||||||
|
|
||||||
// Include the acquisition datetime
|
|
||||||
displaySet.acquisitionDatetime = instance.acquisitionDatetime;
|
|
||||||
|
|
||||||
displaySets.push(displaySet);
|
displaySets.push(displaySet);
|
||||||
} else {
|
} else {
|
||||||
stackableInstances.push(instance);
|
stackableInstances.push(instance);
|
||||||
@ -73,7 +64,7 @@ createStacks = function(study) {
|
|||||||
|
|
||||||
if (stackableInstances.length) {
|
if (stackableInstances.length) {
|
||||||
let displaySet = makeDisplaySet(series, stackableInstances);
|
let displaySet = makeDisplaySet(series, stackableInstances);
|
||||||
displaySet.studyInstanceUid = study.studyInstanceUid;
|
displaySet.setAttribute('studyInstanceUid', study.studyInstanceUid);
|
||||||
displaySets.push(displaySet);
|
displaySets.push(displaySet);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -84,32 +75,32 @@ createStacks = function(study) {
|
|||||||
function makeDisplaySet(series, instances) {
|
function makeDisplaySet(series, instances) {
|
||||||
const instance = instances[0];
|
const instance = instances[0];
|
||||||
|
|
||||||
let displaySet = {
|
const imageSet = new ImageSet(instances);
|
||||||
|
|
||||||
|
// set appropriate attributes to image set...
|
||||||
|
imageSet.setAttributes({
|
||||||
|
displaySetInstanceUid: imageSet.uid, // create a local alias for the imageSet UID
|
||||||
seriesInstanceUid: series.seriesInstanceUid,
|
seriesInstanceUid: series.seriesInstanceUid,
|
||||||
seriesNumber: series.seriesNumber,
|
seriesNumber: series.seriesNumber,
|
||||||
seriesDescription: series.seriesDescription,
|
seriesDescription: series.seriesDescription,
|
||||||
numImageFrames: instances.length,
|
numImageFrames: instances.length,
|
||||||
frameRate: instance.frameTime,
|
frameRate: instance.frameTime,
|
||||||
images: instances,
|
|
||||||
modality: series.modality,
|
modality: series.modality,
|
||||||
isMultiFrame: isMultiFrame(instance)
|
isMultiFrame: isMultiFrame(instance)
|
||||||
};
|
});
|
||||||
|
|
||||||
// Sort the images in this series
|
// Sort the images in this series
|
||||||
displaySet.images.sort(function(a, b) {
|
imageSet.sortBy(function(a, b) {
|
||||||
if (a.instanceNumber && b.instanceNumber &&
|
if (a.instanceNumber && b.instanceNumber &&
|
||||||
a.instanceNumber !== b.instanceNumber) {
|
a.instanceNumber !== b.instanceNumber) {
|
||||||
return a.instanceNumber - b.instanceNumber;
|
return a.instanceNumber - b.instanceNumber;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Include the first image instance number
|
// Include the first image instance number (after sorted)
|
||||||
displaySet.instanceNumber = displaySet.images[0].instanceNumber;
|
imageSet.setAttribute('instanceNumber', imageSet.getImage(0).instanceNumber);
|
||||||
|
|
||||||
// Create a unique ID for this stack so we can reference it
|
return imageSet;
|
||||||
displaySet.displaySetInstanceUid = Random.id();
|
|
||||||
|
|
||||||
return displaySet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSingleImageModality(modality) {
|
function isSingleImageModality(modality) {
|
||||||
@ -121,3 +112,9 @@ function isSingleImageModality(modality) {
|
|||||||
function isMultiFrame(instance) {
|
function isMultiFrame(instance) {
|
||||||
return instance.numFrames > 1;
|
return instance.numFrames > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose "createStacks"...
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { createStacks };
|
||||||
|
|||||||
@ -7,21 +7,30 @@ import { OHIF } from 'meteor/ohif:core';
|
|||||||
*
|
*
|
||||||
* @param element {node} DOM Node representing the viewport element
|
* @param element {node} DOM Node representing the viewport element
|
||||||
*/
|
*/
|
||||||
displayReferenceLines = element => {
|
export function displayReferenceLines(element) {
|
||||||
OHIF.log.info("imageViewerViewport displayReferenceLines");
|
|
||||||
|
|
||||||
// Check if image plane (orientation / loction) data is present for the current image
|
// Check if image plane (orientation / loction) data is present for the current image
|
||||||
const enabledElement = cornerstone.getEnabledElement(element);
|
const enabledElement = cornerstone.getEnabledElement(element);
|
||||||
const imageId = enabledElement.image.imageId;
|
|
||||||
const imagePlane = cornerstoneTools.metaData.get('imagePlane', imageId);
|
|
||||||
|
|
||||||
if (!OHIF.viewer.refLinesEnabled || !imagePlane || !imagePlane.frameOfReferenceUID) {
|
// Check if element is already enabled and it's image was rendered
|
||||||
|
if(!enabledElement || !enabledElement.image) {
|
||||||
|
OHIF.log.info('displayReferenceLines enabled element is undefined or it\'s image is not rendered');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const imageId = enabledElement.image.imageId;
|
||||||
|
const imagePlane = cornerstoneTools.metaData.get('imagePlane', imageId);
|
||||||
|
|
||||||
// Disable reference lines for the current element
|
// Disable reference lines for the current element
|
||||||
cornerstoneTools.referenceLines.tool.disable(element);
|
cornerstoneTools.referenceLines.tool.disable(element);
|
||||||
|
|
||||||
|
if (!OHIF.viewer.refLinesEnabled || !imagePlane || !imagePlane.frameOfReferenceUID) {
|
||||||
|
OHIF.log.info('displayReferenceLines refLinesEnabled is not enabled, no imagePlane or no frameOfReferenceUID');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OHIF.log.info(`displayReferenceLines for image with id: ${imageId}`);
|
||||||
|
|
||||||
// Loop through all other viewport elements and enable reference lines
|
// Loop through all other viewport elements and enable reference lines
|
||||||
$('.imageViewerViewport').not(element).each((index, viewportElement) => {
|
$('.imageViewerViewport').not(element).each((index, viewportElement) => {
|
||||||
let imageId;
|
let imageId;
|
||||||
@ -40,4 +49,4 @@ displayReferenceLines = element => {
|
|||||||
cornerstoneTools.referenceLines.tool.enable(viewportElement, OHIF.viewer.updateImageSynchronizer);
|
cornerstoneTools.referenceLines.tool.enable(viewportElement, OHIF.viewer.updateImageSynchronizer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { Meteor } from "meteor/meteor";
|
import { Meteor } from "meteor/meteor";
|
||||||
|
import { getWADORSImageId } from './getWADORSImageId';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain an imageId for Cornerstone from an image instance
|
* Obtain an imageId for Cornerstone from an image instance
|
||||||
@ -6,17 +7,17 @@ import { Meteor } from "meteor/meteor";
|
|||||||
* @param instance
|
* @param instance
|
||||||
* @returns {string} The imageId to be used by Cornerstone
|
* @returns {string} The imageId to be used by Cornerstone
|
||||||
*/
|
*/
|
||||||
getImageId = function(instance, frame) {
|
export function getImageId(instance, frame) {
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instance.url) {
|
if (instance.url) {
|
||||||
return instance.url;
|
return instance.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instance.wadouri) {
|
if (instance.wadouri) {
|
||||||
var imageId = 'dicomweb:' + Meteor.absoluteUrl(instance.wadouri); // WADO-URI;
|
var imageId = 'dicomweb:' + Meteor.absoluteUrl(instance.wadouri);
|
||||||
if (frame !== undefined) {
|
if (frame !== undefined) {
|
||||||
imageId += '&frame=' + frame;
|
imageId += '&frame=' + frame;
|
||||||
}
|
}
|
||||||
@ -26,4 +27,4 @@ getImageId = function(instance, frame) {
|
|||||||
// TODO= Check multiframe image support with WADO-RS
|
// TODO= Check multiframe image support with WADO-RS
|
||||||
return getWADORSImageId(instance); // WADO-RS Retrieve Frame
|
return getWADORSImageId(instance); // WADO-RS Retrieve Frame
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { OHIF } from 'meteor/ohif:core';
|
|||||||
* @returns {string} The imageId to be used by Cornerstone
|
* @returns {string} The imageId to be used by Cornerstone
|
||||||
*/
|
*/
|
||||||
|
|
||||||
getWADORSImageId = function(instance) {
|
export function getWADORSImageId(instance) {
|
||||||
var columnPixelSpacing = 1.0;
|
var columnPixelSpacing = 1.0;
|
||||||
var rowPixelSpacing = 1.0;
|
var rowPixelSpacing = 1.0;
|
||||||
if (instance.pixelSpacing) {
|
if (instance.pixelSpacing) {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper to capitalizes the first letter of an input String
|
* A global Blaze UI helper to capitalizes the first letter of an input String
|
||||||
*
|
*
|
||||||
@ -5,10 +7,10 @@
|
|||||||
*
|
*
|
||||||
* http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
|
* http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('capitalizeFirstLetter', function (context) {
|
Blaze.registerHelper('capitalizeFirstLetter', function (context) {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.charAt(0).toUpperCase() + context.slice(1);
|
return context.charAt(0).toUpperCase() + context.slice(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { moment } from 'meteor/momentjs:moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper function to format DICOM Dates using the Moment library
|
* A global Blaze UI helper function to format DICOM Dates using the Moment library
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('formatDA', function (context, format, options) {
|
|
||||||
|
const formatDA = (context, format, options) => {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -11,4 +15,8 @@ UI.registerHelper('formatDA', function (context, format, options) {
|
|||||||
strFormat = format;
|
strFormat = format;
|
||||||
}
|
}
|
||||||
return dateAsMoment.format(strFormat);
|
return dateAsMoment.format(strFormat);
|
||||||
});
|
};
|
||||||
|
|
||||||
|
Blaze.registerHelper('formatDA', formatDA);
|
||||||
|
|
||||||
|
export { formatDA };
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { moment } from 'meteor/momentjs:moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper function to format JavaScript Dates using the Moment library
|
* A global Blaze UI helper function to format JavaScript Dates using the Moment library
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('formatJSDate', function(context, format, options) {
|
Blaze.registerHelper('formatJSDate', function(context, format, options) {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper to format a float value to a specified precision
|
* A global Blaze UI helper to format a float value to a specified precision
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('formatNumberPrecision', function(context, precision) {
|
Blaze.registerHelper('formatNumberPrecision', function(context, precision) {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
return parseFloat(context).toFixed(precision);
|
return parseFloat(context).toFixed(precision);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
/**
|
/**
|
||||||
* Formats a patient name for display purposes
|
* Formats a patient name for display purposes
|
||||||
*/
|
*/
|
||||||
formatPN = function(context) {
|
const formatPN = context => {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -11,4 +12,6 @@ formatPN = function(context) {
|
|||||||
/**
|
/**
|
||||||
* A global Blaze UI helper to format a patient name for display purposes
|
* A global Blaze UI helper to format a patient name for display purposes
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('formatPN', formatPN);
|
Blaze.registerHelper('formatPN', formatPN);
|
||||||
|
|
||||||
|
export { formatPN };
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { moment } from 'meteor/momentjs:moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper to format a DICOM Time for display using the Moment library
|
* A global Blaze UI helper to format a DICOM Time for display using the Moment library
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('formatTM', function(context, options) {
|
|
||||||
|
const formatTM = (context, options) => {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -21,4 +25,8 @@ UI.registerHelper('formatTM', function(context, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return dateTime.format(format);
|
return dateTime.format(format);
|
||||||
});
|
};
|
||||||
|
|
||||||
|
Blaze.registerHelper('formatTM', formatTM);
|
||||||
|
|
||||||
|
export { formatTM };
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for retrieving username given userId
|
* Helper for retrieving username given userId
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('getUsername', function(userId) {
|
Blaze.registerHelper('getUsername', function(userId) {
|
||||||
var user = Meteor.users.findOne({
|
var user = Meteor.users.findOne({
|
||||||
userId: userId
|
userId: userId
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for checking datatype of a variable
|
* Helper for checking datatype of a variable
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('ifTypeIs', function(value, match, attributeName) {
|
Blaze.registerHelper('ifTypeIs', function(value, match, attributeName) {
|
||||||
if (typeof(value) === match) {
|
if (typeof(value) === match) {
|
||||||
return attributeName;
|
return attributeName;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
UI.registerHelper('inc', function(value) {
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
|
Blaze.registerHelper('inc', function(value) {
|
||||||
return parseInt(value) + 1;
|
return parseInt(value) + 1;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
|
import { viewportUtils } from '../viewportUtils';
|
||||||
|
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import 'meteor/ohif:viewerbase';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boolean helper to identify if a series instance is active in some viewport
|
* Boolean helper to identify if a series instance is active in some viewport
|
||||||
*/
|
*/
|
||||||
@ -6,7 +14,7 @@ Template.registerHelper('isDisplaySetActive', (displaySetInstanceUid, viewportIn
|
|||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
// Stop here if layoutManager is not defined yet
|
// Stop here if layoutManager is not defined yet
|
||||||
if (!window.layoutManager) {
|
if (!OHIF.viewerbase.layoutManager) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,22 +30,28 @@ Template.registerHelper('isDisplaySetActive', (displaySetInstanceUid, viewportIn
|
|||||||
if (_.isUndefined(viewportIndex)) {
|
if (_.isUndefined(viewportIndex)) {
|
||||||
// Get the number of viewports that are currently displayed
|
// Get the number of viewports that are currently displayed
|
||||||
// (Note, viewportData may have more entries!)
|
// (Note, viewportData may have more entries!)
|
||||||
const currentNumberOfViewports = layoutManager.getNumberOfViewports();
|
const currentNumberOfViewports = OHIF.viewerbase.layoutManager.getNumberOfViewports();
|
||||||
|
|
||||||
|
// Get active viewport element
|
||||||
|
const activeViewport = viewportUtils.getActiveViewportElement();
|
||||||
|
|
||||||
|
// Get viewports elements
|
||||||
|
const viewportsElement = $('.imageViewerViewport');
|
||||||
|
|
||||||
// Loop through the viewport data up until the currently displayed
|
// Loop through the viewport data up until the currently displayed
|
||||||
// number of viewports
|
// number of viewports
|
||||||
let viewportData = window.layoutManager.viewportData;
|
const viewportData = OHIF.viewerbase.layoutManager.viewportData;
|
||||||
for (let i = 0; i < currentNumberOfViewports; i++) {
|
for (let i = 0; i < currentNumberOfViewports; i++) {
|
||||||
const data = viewportData[i];
|
const data = viewportData[i];
|
||||||
|
|
||||||
// If the display set is displayed in this viewport, stop here
|
// If the display set is displayed in this viewport and is active, stop here
|
||||||
if (data && data.displaySetInstanceUid === displaySetInstanceUid) {
|
if (data && data.displaySetInstanceUid === displaySetInstanceUid && viewportsElement.get(data.viewportIndex) === activeViewport) {
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const data = window.layoutManager.viewportData[viewportIndex];
|
const data = OHIF.viewerbase.layoutManager.viewportData[viewportIndex];
|
||||||
|
|
||||||
// If the display set is displayed in this viewport, stop here
|
// If the display set is displayed in this viewport, stop here
|
||||||
if (data && data.displaySetInstanceUid === displaySetInstanceUid) {
|
if (data && data.displaySetInstanceUid === displaySetInstanceUid) {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to determine if the current client devices
|
* Helper function to determine if the current client devices
|
||||||
* is touch-capable. This can be used to modify certain aspects of the UI.
|
* is touch-capable. This can be used to modify certain aspects of the UI.
|
||||||
@ -6,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
* @returns {boolean} true if the client device is touch-capable, false otherwise
|
* @returns {boolean} true if the client device is touch-capable, false otherwise
|
||||||
*/
|
*/
|
||||||
isTouchDevice = function() {
|
const isTouchDevice = () => {
|
||||||
return (('ontouchstart' in window) ||
|
return (('ontouchstart' in window) ||
|
||||||
(navigator.MaxTouchPoints > 0) ||
|
(navigator.MaxTouchPoints > 0) ||
|
||||||
(navigator.msMaxTouchPoints > 0));
|
(navigator.msMaxTouchPoints > 0));
|
||||||
@ -17,4 +19,6 @@ isTouchDevice = function() {
|
|||||||
*
|
*
|
||||||
* @returns {boolean} true if the client device is touch-capable, false otherwise
|
* @returns {boolean} true if the client device is touch-capable, false otherwise
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('isTouchDevice', isTouchDevice);
|
Blaze.registerHelper('isTouchDevice', isTouchDevice);
|
||||||
|
|
||||||
|
export { isTouchDevice };
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { moment } from 'meteor/momentjs:moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper function to format JavaScript Dates using the Moment library
|
* A global Blaze UI helper function to format JavaScript Dates using the Moment library
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('jsDateFromNow', function(context, format, options) {
|
Blaze.registerHelper('jsDateFromNow', function(context, format, options) {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
UI.registerHelper('objectEach', function(object) {
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
|
Blaze.registerHelper('objectEach', function(object) {
|
||||||
// http://stackoverflow.com/questions/30234732/how-to-print-key-and-values-in-meteor-template
|
// http://stackoverflow.com/questions/30234732/how-to-print-key-and-values-in-meteor-template
|
||||||
return _.map(object, function(value, key) {
|
return _.map(object, function(value, key) {
|
||||||
return _.extend({key: key}, value);
|
return _.extend({key: key}, value);
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
UI.registerHelper('objectToPairs', function(object) {
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
|
Blaze.registerHelper('objectToPairs', function(object) {
|
||||||
// http://stackoverflow.com/questions/30234732/how-to-print-key-and-values-in-meteor-template
|
// http://stackoverflow.com/questions/30234732/how-to-print-key-and-values-in-meteor-template
|
||||||
return _.map(object, function(value, key) {
|
return _.map(object, function(value, key) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper to Stringify a JavaScript object
|
* A global Blaze UI helper to Stringify a JavaScript object
|
||||||
*
|
*
|
||||||
@ -5,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
|
* http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
|
||||||
*/
|
*/
|
||||||
UI.registerHelper('prettyPrintStringify', function(context) {
|
Blaze.registerHelper('prettyPrintStringify', function(context) {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { _ } from 'meteor/underscore';
|
|
||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global Blaze UI helper to sort array elements
|
* Global Blaze UI helper to sort array elements
|
||||||
@ -54,4 +54,4 @@ function getKeyValue(object, keyPath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper to get the thumbnails for the given study
|
* A global Blaze UI helper to get the thumbnails for the given study
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
var instanceClassViewportSettingsFunctions = {};
|
|
||||||
getInstanceClassDefaultViewport = function(series, enabledElement, imageId) {
|
const instanceClassViewportSettingsFunctions = {};
|
||||||
var instanceClass = series.sopClassUid;
|
|
||||||
|
const getInstanceClassDefaultViewport = (series, enabledElement, imageId) => {
|
||||||
|
let instanceClass = series.sopClassUid;
|
||||||
|
|
||||||
if (!instanceClassViewportSettingsFunctions[instanceClass]) {
|
if (!instanceClassViewportSettingsFunctions[instanceClass]) {
|
||||||
return;
|
return;
|
||||||
@ -9,6 +11,8 @@ getInstanceClassDefaultViewport = function(series, enabledElement, imageId) {
|
|||||||
return instanceClassViewportSettingsFunctions[instanceClass](series, enabledElement, imageId);
|
return instanceClassViewportSettingsFunctions[instanceClass](series, enabledElement, imageId);
|
||||||
};
|
};
|
||||||
|
|
||||||
setInstanceClassDefaultViewportFunction = function(instanceClass, fn) {
|
const setInstanceClassDefaultViewportFunction = (instanceClass, fn) => {
|
||||||
instanceClassViewportSettingsFunctions[instanceClass] = fn;
|
instanceClassViewportSettingsFunctions[instanceClass] = fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { getInstanceClassDefaultViewport, setInstanceClassDefaultViewportFunction };
|
||||||
|
|||||||
@ -1,59 +1,61 @@
|
|||||||
|
import { sopClassDictionary } from './sopClassDictionary';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether dicom files with specified SOP Class UID have image data
|
* Checks whether dicom files with specified SOP Class UID have image data
|
||||||
* @param {string} sopClassUid - SOP Class UID to be checked
|
* @param {string} sopClassUid - SOP Class UID to be checked
|
||||||
* @returns {boolean} - true if it has image data
|
* @returns {boolean} - true if it has image data
|
||||||
*/
|
*/
|
||||||
isImage = function(sopClassUid) {
|
export function isImage(sopClassUid) {
|
||||||
if (sopClassUid == sopClassDictionary.ComputedRadiographyImageStorage
|
if (sopClassUid === sopClassDictionary.ComputedRadiographyImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.DigitalXRayImageStorageForPresentation
|
|| sopClassUid === sopClassDictionary.DigitalXRayImageStorageForPresentation
|
||||||
|| sopClassUid == sopClassDictionary.DigitalXRayImageStorageForProcessing
|
|| sopClassUid === sopClassDictionary.DigitalXRayImageStorageForProcessing
|
||||||
|| sopClassUid == sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation
|
|| sopClassUid === sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation
|
||||||
|| sopClassUid == sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing
|
|| sopClassUid === sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing
|
||||||
|| sopClassUid == sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation
|
|| sopClassUid === sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation
|
||||||
|| sopClassUid == sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing
|
|| sopClassUid === sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing
|
||||||
|| sopClassUid == sopClassDictionary.CTImageStorage
|
|| sopClassUid === sopClassDictionary.CTImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.EnhancedCTImageStorage
|
|| sopClassUid === sopClassDictionary.EnhancedCTImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.LegacyConvertedEnhancedCTImageStorage
|
|| sopClassUid === sopClassDictionary.LegacyConvertedEnhancedCTImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.UltrasoundMultiframeImageStorage
|
|| sopClassUid === sopClassDictionary.UltrasoundMultiframeImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.MRImageStorage
|
|| sopClassUid === sopClassDictionary.MRImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.EnhancedMRImageStorage
|
|| sopClassUid === sopClassDictionary.EnhancedMRImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.EnhancedMRColorImageStorage
|
|| sopClassUid === sopClassDictionary.EnhancedMRColorImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.LegacyConvertedEnhancedMRImageStorage
|
|| sopClassUid === sopClassDictionary.LegacyConvertedEnhancedMRImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.UltrasoundImageStorage
|
|| sopClassUid === sopClassDictionary.UltrasoundImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.SecondaryCaptureImageStorage
|
|| sopClassUid === sopClassDictionary.SecondaryCaptureImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage
|
|| sopClassUid === sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage
|
|| sopClassUid === sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage
|
|| sopClassUid === sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage
|
|| sopClassUid === sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.XRayAngiographicImageStorage
|
|| sopClassUid === sopClassDictionary.XRayAngiographicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.EnhancedXAImageStorage
|
|| sopClassUid === sopClassDictionary.EnhancedXAImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.XRayRadiofluoroscopicImageStorage
|
|| sopClassUid === sopClassDictionary.XRayRadiofluoroscopicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.EnhancedXRFImageStorage
|
|| sopClassUid === sopClassDictionary.EnhancedXRFImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.XRay3DAngiographicImageStorage
|
|| sopClassUid === sopClassDictionary.XRay3DAngiographicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.XRay3DCraniofacialImageStorage
|
|| sopClassUid === sopClassDictionary.XRay3DCraniofacialImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.BreastTomosynthesisImageStorage
|
|| sopClassUid === sopClassDictionary.BreastTomosynthesisImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.BreastProjectionXRayImageStorageForPresentation
|
|| sopClassUid === sopClassDictionary.BreastProjectionXRayImageStorageForPresentation
|
||||||
|| sopClassUid == sopClassDictionary.BreastProjectionXRayImageStorageForProcessing
|
|| sopClassUid === sopClassDictionary.BreastProjectionXRayImageStorageForProcessing
|
||||||
|| sopClassUid == sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation
|
|| sopClassUid === sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation
|
||||||
|| sopClassUid == sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing
|
|| sopClassUid === sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing
|
||||||
|| sopClassUid == sopClassDictionary.NuclearMedicineImageStorage
|
|| sopClassUid === sopClassDictionary.NuclearMedicineImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VLEndoscopicImageStorage
|
|| sopClassUid === sopClassDictionary.VLEndoscopicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VideoEndoscopicImageStorage
|
|| sopClassUid === sopClassDictionary.VideoEndoscopicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VLMicroscopicImageStorage
|
|| sopClassUid === sopClassDictionary.VLMicroscopicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VideoMicroscopicImageStorage
|
|| sopClassUid === sopClassDictionary.VideoMicroscopicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage
|
|| sopClassUid === sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VLPhotographicImageStorage
|
|| sopClassUid === sopClassDictionary.VLPhotographicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VideoPhotographicImageStorage
|
|| sopClassUid === sopClassDictionary.VideoPhotographicImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.OphthalmicPhotography8BitImageStorage
|
|| sopClassUid === sopClassDictionary.OphthalmicPhotography8BitImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.OphthalmicPhotography16BitImageStorage
|
|| sopClassUid === sopClassDictionary.OphthalmicPhotography16BitImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.OphthalmicTomographyImageStorage
|
|| sopClassUid === sopClassDictionary.OphthalmicTomographyImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.VLWholeSlideMicroscopyImageStorage
|
|| sopClassUid === sopClassDictionary.VLWholeSlideMicroscopyImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.PositronEmissionTomographyImageStorage
|
|| sopClassUid === sopClassDictionary.PositronEmissionTomographyImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.EnhancedPETImageStorage
|
|| sopClassUid === sopClassDictionary.EnhancedPETImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.LegacyConvertedEnhancedPETImageStorage
|
|| sopClassUid === sopClassDictionary.LegacyConvertedEnhancedPETImageStorage
|
||||||
|| sopClassUid == sopClassDictionary.RTImageStorage) {
|
|| sopClassUid === sopClassDictionary.RTImageStorage) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {parsingUtils} from './parsingUtils'
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { parsingUtils } from './parsingUtils';
|
||||||
|
|
||||||
var metaDataLookup = {};
|
const metaDataLookup = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cornerstone MetaData provider to store image meta data
|
* Cornerstone MetaData provider to store image meta data
|
||||||
@ -14,14 +15,14 @@ var metaDataLookup = {};
|
|||||||
* @param {String} imageId The Cornerstone ImageId
|
* @param {String} imageId The Cornerstone ImageId
|
||||||
* @param {Object} data An object containing instance, series, and study metaData
|
* @param {Object} data An object containing instance, series, and study metaData
|
||||||
*/
|
*/
|
||||||
addMetaData = function(imageId, data) {
|
const addMetaData = (imageId, data) => {
|
||||||
var instanceMetaData = data.instance;
|
let instanceMetaData = data.instance;
|
||||||
var seriesMetaData = data.series;
|
let seriesMetaData = data.series;
|
||||||
var studyMetaData = data.study;
|
let studyMetaData = data.study;
|
||||||
var imageIndex = data.imageIndex;
|
let imageIndex = data.imageIndex;
|
||||||
var numImages = data.numImages;
|
let numImages = data.numImages;
|
||||||
|
|
||||||
var metaData = {};
|
let metaData = {};
|
||||||
|
|
||||||
metaData.study = {
|
metaData.study = {
|
||||||
patientId: studyMetaData.patientId,
|
patientId: studyMetaData.patientId,
|
||||||
@ -66,8 +67,8 @@ addMetaData = function(imageId, data) {
|
|||||||
* @param type (e.g. series, instance, tagDisplay)
|
* @param type (e.g. series, instance, tagDisplay)
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
addSpecificMetadata = function(imageId, type, data) {
|
const addSpecificMetadata = (imageId, type, data) => {
|
||||||
var metaData = {};
|
let metaData = {};
|
||||||
metaData[type] = data;
|
metaData[type] = data;
|
||||||
|
|
||||||
metaDataLookup[imageId] = $.extend(metaDataLookup[imageId], metaData);
|
metaDataLookup[imageId] = $.extend(metaDataLookup[imageId], metaData);
|
||||||
@ -92,8 +93,8 @@ function getFromDataSet(dataSet, type, tag) {
|
|||||||
*
|
*
|
||||||
* @param image
|
* @param image
|
||||||
*/
|
*/
|
||||||
updateMetaData = function(image) {
|
const updateMetaData = image => {
|
||||||
var imageMetaData = metaDataLookup[image.imageId];
|
const imageMetaData = metaDataLookup[image.imageId];
|
||||||
if (!imageMetaData) {
|
if (!imageMetaData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -141,13 +142,13 @@ function getImagePlane(instance) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageOrientation = instance.imageOrientationPatient.split('\\');
|
let imageOrientation = instance.imageOrientationPatient.split('\\');
|
||||||
var imagePosition = instance.imagePositionPatient.split('\\');
|
let imagePosition = instance.imagePositionPatient.split('\\');
|
||||||
|
|
||||||
var columnPixelSpacing = 1.0;
|
let columnPixelSpacing = 1.0;
|
||||||
var rowPixelSpacing = 1.0;
|
let rowPixelSpacing = 1.0;
|
||||||
if (instance.pixelSpacing) {
|
if (instance.pixelSpacing) {
|
||||||
var split = instance.pixelSpacing.split('\\');
|
let split = instance.pixelSpacing.split('\\');
|
||||||
rowPixelSpacing = parseFloat(split[0]);
|
rowPixelSpacing = parseFloat(split[0]);
|
||||||
columnPixelSpacing = parseFloat(split[1]);
|
columnPixelSpacing = parseFloat(split[1]);
|
||||||
}
|
}
|
||||||
@ -178,9 +179,9 @@ function getImagePlane(instance) {
|
|||||||
* @param dataSet {Object} An instance of dicomParser.DataSet object where multiframe information can be found.
|
* @param dataSet {Object} An instance of dicomParser.DataSet object where multiframe information can be found.
|
||||||
* @return {Object} An object containing multiframe image metadata (frameIncrementPointer, frameTime, frameTimeVector, etc).
|
* @return {Object} An object containing multiframe image metadata (frameIncrementPointer, frameTime, frameTimeVector, etc).
|
||||||
*/
|
*/
|
||||||
getMultiframeModuleMetaData = function(dataSet) {
|
function getMultiframeModuleMetaData(dataSet) {
|
||||||
|
|
||||||
var numberOfFrames,
|
let numberOfFrames,
|
||||||
frameIncrementPointer,
|
frameIncrementPointer,
|
||||||
frameTime,
|
frameTime,
|
||||||
frameTimeVector,
|
frameTimeVector,
|
||||||
@ -232,7 +233,7 @@ getMultiframeModuleMetaData = function(dataSet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return imageInfo;
|
return imageInfo;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up metaData for Cornerstone Tools given a specified type and imageId
|
* Looks up metaData for Cornerstone Tools given a specified type and imageId
|
||||||
@ -244,7 +245,7 @@ getMultiframeModuleMetaData = function(dataSet) {
|
|||||||
* @returns {Object} Relevant metaData of the specified type
|
* @returns {Object} Relevant metaData of the specified type
|
||||||
*/
|
*/
|
||||||
function provider(type, imageId) {
|
function provider(type, imageId) {
|
||||||
var imageMetaData = metaDataLookup[imageId];
|
let imageMetaData = metaDataLookup[imageId];
|
||||||
if (!imageMetaData) {
|
if (!imageMetaData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -257,3 +258,9 @@ function provider(type, imageId) {
|
|||||||
Meteor.startup(function() {
|
Meteor.startup(function() {
|
||||||
cornerstoneTools.metaData.addProvider(provider);
|
cornerstoneTools.metaData.addProvider(provider);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export relevant symbols
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { addMetaData, addSpecificMetadata, updateMetaData };
|
||||||
|
|||||||
@ -1,14 +1,32 @@
|
|||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import { enablePrefetchOnElement } from './enablePrefetchOnElement';
|
||||||
|
import { displayReferenceLines } from './displayReferenceLines';
|
||||||
|
|
||||||
setActiveViewport = element => {
|
/**
|
||||||
|
* Sets a viewport element active
|
||||||
|
* @param {node} element DOM element to be activated
|
||||||
|
*/
|
||||||
|
export function setActiveViewport(element) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
|
OHIF.log.info('setActiveViewport element does not exist');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewportIndex = $('.imageViewerViewport').index(element);
|
const viewerports = $('.imageViewerViewport');
|
||||||
|
const viewportIndex = viewerports.index(element);
|
||||||
const jQueryElement = $(element);
|
const jQueryElement = $(element);
|
||||||
|
|
||||||
// When an ActivateViewport event is fired, update the Meteor Session
|
OHIF.log.info(`setActiveViewport setting viewport index: ${viewportIndex}`);
|
||||||
|
|
||||||
|
// If viewport is not active
|
||||||
|
if(!jQueryElement.parents('.viewportContainer').hasClass('active')) {
|
||||||
|
// Trigger an event for compatibility with other systems
|
||||||
|
jQueryElement.trigger('OHIFBeforeActivateViewport');
|
||||||
|
}
|
||||||
|
|
||||||
|
// When an OHIFActivateViewport event is fired, update the Meteor Session
|
||||||
// with the viewport index that it was fired from.
|
// with the viewport index that it was fired from.
|
||||||
Session.set('activeViewport', viewportIndex);
|
Session.set('activeViewport', viewportIndex);
|
||||||
|
|
||||||
@ -28,11 +46,19 @@ setActiveViewport = element => {
|
|||||||
const domElement = jQueryElement.get(0);
|
const domElement = jQueryElement.get(0);
|
||||||
enablePrefetchOnElement(domElement);
|
enablePrefetchOnElement(domElement);
|
||||||
displayReferenceLines(domElement);
|
displayReferenceLines(domElement);
|
||||||
OHIF.viewer.stackImagePositionOffsetSynchronizer.update();
|
// @TODO Add this to OHIFAfterActivateViewport handler...
|
||||||
|
if (OHIF.viewer.stackImagePositionOffsetSynchronizer) {
|
||||||
|
OHIF.viewer.stackImagePositionOffsetSynchronizer.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the div to focused, so keypress events are handled
|
// Set the div to focused, so keypress events are handled
|
||||||
//$(element).focus();
|
//$(element).focus();
|
||||||
//.focus() event breaks in FF&IE
|
//.focus() event breaks in FF&IE
|
||||||
jQueryElement.triggerHandler('focus');
|
jQueryElement.triggerHandler('focus');
|
||||||
};
|
|
||||||
|
// Trigger OHIFAfterActivateViewport event on activated instance
|
||||||
|
// for compatibility with other systems
|
||||||
|
jQueryElement.trigger('OHIFAfterActivateViewport');
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,19 +1,24 @@
|
|||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the browser focus to the currently specified active viewport
|
* Restores the browser focus to the currently specified active viewport
|
||||||
* as determined from Meteor's Session variable.
|
* as determined from Meteor's Session variable.
|
||||||
*
|
*
|
||||||
* This is allows keydown events to be captured on the focused element
|
* This is allows keydown events to be captured on the focused element.
|
||||||
*/
|
*/
|
||||||
setFocusToActiveViewport = function() {
|
const setFocusToActiveViewport = () => {
|
||||||
// Get the list of viewports
|
// Get the list of viewports
|
||||||
var viewports = $('.imageViewerViewport');
|
const viewports = $('.imageViewerViewport');
|
||||||
|
|
||||||
// Get the current active viewport index from Session
|
// Get the current active viewport index from Session
|
||||||
var activeViewportIndex = Session.get('activeViewport');
|
const activeViewportIndex = Session.get('activeViewport');
|
||||||
|
|
||||||
// Find the div from the list of viewports
|
// Find the div from the list of viewports
|
||||||
var activeViewport = viewports.eq(activeViewportIndex);
|
const activeViewport = viewports.eq(activeViewportIndex);
|
||||||
|
|
||||||
// Set the browser focus to this div
|
// Set the browser focus to this div
|
||||||
activeViewport.focus();
|
activeViewport.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { setFocusToActiveViewport };
|
||||||
@ -1,19 +1,24 @@
|
|||||||
setMammogramViewportAlignment = function(series, enabledElement, imageId) {
|
import { Meteor } from 'meteor/meteor';
|
||||||
// Don't apply the MG viewport alignment to other series types
|
import { $ } from 'meteor/jquery';
|
||||||
var viewTypes = ['MLO', 'CC', 'LM', 'ML', 'XCCL'];
|
import { setInstanceClassDefaultViewportFunction } from './instanceClassSpecificViewport';
|
||||||
var requiresInversion = ['LM']; // Tomo series are flipped
|
import { addSpecificMetadata } from './metaDataProvider';
|
||||||
|
|
||||||
var instance = cornerstoneTools.metaData.get('instance', imageId);
|
const setMammogramViewportAlignment = (series, enabledElement, imageId) => {
|
||||||
|
// Don't apply the MG viewport alignment to other series types
|
||||||
|
let viewTypes = ['MLO', 'CC', 'LM', 'ML', 'XCCL'];
|
||||||
|
let requiresInversion = ['LM']; // Tomo series are flipped
|
||||||
|
|
||||||
|
let instance = cornerstoneTools.metaData.get('instance', imageId);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var laterality = instance.laterality;
|
let laterality = instance.laterality;
|
||||||
var element = enabledElement.element;
|
let element = enabledElement.element;
|
||||||
var position;
|
let position;
|
||||||
|
|
||||||
var left = $(enabledElement.canvas).offset().left;
|
let left = $(enabledElement.canvas).offset().left;
|
||||||
var right = left + enabledElement.canvas.width;
|
let right = left + enabledElement.canvas.width;
|
||||||
|
|
||||||
if (viewTypes.indexOf(instance.viewPosition) < 0) {
|
if (viewTypes.indexOf(instance.viewPosition) < 0) {
|
||||||
return;
|
return;
|
||||||
@ -58,4 +63,6 @@ setMammogramViewportAlignment = function(series, enabledElement, imageId) {
|
|||||||
|
|
||||||
Meteor.startup(function() {
|
Meteor.startup(function() {
|
||||||
setInstanceClassDefaultViewportFunction("1.2.840.10008.5.1.4.1.1.1.2", setMammogramViewportAlignment);
|
setInstanceClassDefaultViewportFunction("1.2.840.10008.5.1.4.1.1.1.2", setMammogramViewportAlignment);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export { setMammogramViewportAlignment };
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
sopClassDictionary = {
|
|
||||||
|
export const sopClassDictionary = {
|
||||||
ComputedRadiographyImageStorage: "1.2.840.10008.5.1.4.1.1.1",
|
ComputedRadiographyImageStorage: "1.2.840.10008.5.1.4.1.1.1",
|
||||||
DigitalXRayImageStorageForPresentation: "1.2.840.10008.5.1.4.1.1.1.1",
|
DigitalXRayImageStorageForPresentation: "1.2.840.10008.5.1.4.1.1.1.1",
|
||||||
DigitalXRayImageStorageForProcessing: "1.2.840.10008.5.1.4.1.1.1.1.1",
|
DigitalXRayImageStorageForProcessing: "1.2.840.10008.5.1.4.1.1.1.1.1",
|
||||||
@ -112,4 +113,4 @@ sopClassDictionary = {
|
|||||||
GenericImplantTemplateStorage: "1.2.840.10008.5.1.4.43.1",
|
GenericImplantTemplateStorage: "1.2.840.10008.5.1.4.43.1",
|
||||||
ImplantAssemblyTemplateStorage: "1.2.840.10008.5.1.4.44.1",
|
ImplantAssemblyTemplateStorage: "1.2.840.10008.5.1.4.44.1",
|
||||||
ImplantTemplateGroupStorage: "1.2.840.10008.5.1.4.45.1"
|
ImplantTemplateGroupStorage: "1.2.840.10008.5.1.4.45.1"
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,21 +1,19 @@
|
|||||||
|
import { OHIFError } from './classes/OHIFError';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the series and instances inside a study instance by their series
|
* Sorts the series and instances inside a study instance by their series
|
||||||
* and instance numbers in ascending order.
|
* and instance numbers in ascending order.
|
||||||
*
|
*
|
||||||
* @param {Object} study The study instance
|
* @param {Object} study The study instance
|
||||||
*/
|
*/
|
||||||
sortStudy = function(study) {
|
export function sortStudy(study) {
|
||||||
if (!study || !study.seriesList) {
|
if (!study || !study.seriesList) {
|
||||||
throw "Insufficient study data was provided to sortStudy";
|
throw new OHIFError('Insufficient study data was provided to sortStudy');
|
||||||
}
|
}
|
||||||
|
|
||||||
study.seriesList.sort(function(a, b) {
|
|
||||||
return a.seriesNumber - b.seriesNumber;
|
|
||||||
});
|
|
||||||
|
|
||||||
study.seriesList.forEach(function(series){
|
study.seriesList.sort((a, b) => a.seriesNumber - b.seriesNumber);
|
||||||
series.instances.sort(function(a, b) {
|
|
||||||
return a.instanceNumber - b.instanceNumber;
|
study.seriesList.forEach(series => {
|
||||||
});
|
series.instances.sort((a, b) => a.instanceNumber - b.instanceNumber);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { viewportUtils } from './viewportUtils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function switches to an image given an element and the index of the image in the current stack
|
* This function switches to an image given an element and the index of the image in the current stack
|
||||||
* Note: Negative indexing is supported:
|
* Note: Negative indexing is supported:
|
||||||
@ -7,7 +9,7 @@
|
|||||||
* @param element
|
* @param element
|
||||||
* @param {number} [newImageIdIndex] The image index in the stack to switch to.
|
* @param {number} [newImageIdIndex] The image index in the stack to switch to.
|
||||||
*/
|
*/
|
||||||
switchToImageByIndex = function(newImageIdIndex) {
|
export function switchToImageByIndex(newImageIdIndex) {
|
||||||
var element = getActiveViewportElement();
|
var element = viewportUtils.getActiveViewportElement();
|
||||||
cornerstoneTools.scrollToIndex(element, newImageIdIndex);
|
cornerstoneTools.scrollToIndex(element, newImageIdIndex);
|
||||||
};
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { viewportUtils } from './viewportUtils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function switches to an image given an element and
|
* This function switches to an image given an element and
|
||||||
* the relative distance from the current image in the stack
|
* the relative distance from the current image in the stack
|
||||||
@ -7,7 +9,7 @@
|
|||||||
* @param element
|
* @param element
|
||||||
* @param {number} [distanceFromCurrentIndex] The image index in the stack to switch to.
|
* @param {number} [distanceFromCurrentIndex] The image index in the stack to switch to.
|
||||||
*/
|
*/
|
||||||
switchToImageRelative = function(distanceFromCurrentIndex) {
|
export function switchToImageRelative(distanceFromCurrentIndex) {
|
||||||
var element = getActiveViewportElement();
|
var element = viewportUtils.getActiveViewportElement();
|
||||||
cornerstoneTools.scroll(element, distanceFromCurrentIndex);
|
cornerstoneTools.scroll(element, distanceFromCurrentIndex);
|
||||||
};
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
updateAllViewports = function() {
|
import { $ } from 'meteor/jquery';
|
||||||
|
|
||||||
|
export function updateAllViewports() {
|
||||||
var viewports = $('.imageViewerViewport').not('.empty');
|
var viewports = $('.imageViewerViewport').not('.empty');
|
||||||
viewports.each(function(index, element) {
|
viewports.each(function(index, element) {
|
||||||
cornerstone.updateImage(element);
|
cornerstone.updateImage(element);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { Random } from 'meteor/random';
|
|||||||
import { $ } from 'meteor/jquery';
|
import { $ } from 'meteor/jquery';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
// Local Modules
|
// Local Modules
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { updateOrientationMarkers } from './updateOrientationMarkers';
|
import { updateOrientationMarkers } from './updateOrientationMarkers';
|
||||||
import { getInstanceClassDefaultViewport } from './instanceClassSpecificViewport';
|
import { getInstanceClassDefaultViewport } from './instanceClassSpecificViewport';
|
||||||
|
|
||||||
@ -120,6 +121,16 @@ function clearTools() {
|
|||||||
cornerstone.updateImage(element);
|
cornerstone.updateImage(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function linkStackScroll() {
|
||||||
|
const synchronizer = OHIF.viewer.stackImagePositionOffsetSynchronizer;
|
||||||
|
|
||||||
|
if(synchronizer.isActive()) {
|
||||||
|
synchronizer.deactivate();
|
||||||
|
} else {
|
||||||
|
synchronizer.activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This function was originally defined alone inside client/lib/toggleDialog.js
|
// This function was originally defined alone inside client/lib/toggleDialog.js
|
||||||
// and has been moved here to avoid circular dependency issues.
|
// and has been moved here to avoid circular dependency issues.
|
||||||
function toggleDialog(element) {
|
function toggleDialog(element) {
|
||||||
@ -238,6 +249,17 @@ function stopAllClips() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function isStackScrollLinkingDisabled() {
|
||||||
|
// Its called everytime active viewport and/or layout change
|
||||||
|
Session.get('activeViewport');
|
||||||
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
|
const synchronizer = OHIF.viewer.stackImagePositionOffsetSynchronizer;
|
||||||
|
const linkableViewports = synchronizer.getLinkableViewports();
|
||||||
|
|
||||||
|
return linkableViewports.length <= 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Create an event listener to update playing state when a clip stops playing
|
// Create an event listener to update playing state when a clip stops playing
|
||||||
$(window).on('CornerstoneToolsClipStopped', () => Session.set('UpdateCINE', Random.id()));
|
$(window).on('CornerstoneToolsClipStopped', () => Session.set('UpdateCINE', Random.id()));
|
||||||
|
|
||||||
@ -257,12 +279,14 @@ const viewportUtils = {
|
|||||||
flipH,
|
flipH,
|
||||||
resetViewport,
|
resetViewport,
|
||||||
clearTools,
|
clearTools,
|
||||||
|
linkStackScroll,
|
||||||
toggleDialog,
|
toggleDialog,
|
||||||
toggleCinePlay,
|
toggleCinePlay,
|
||||||
toggleCineDialog,
|
toggleCineDialog,
|
||||||
isPlaying,
|
isPlaying,
|
||||||
hasMultipleFrames,
|
hasMultipleFrames,
|
||||||
stopAllClips
|
stopAllClips,
|
||||||
|
isStackScrollLinkingDisabled
|
||||||
};
|
};
|
||||||
|
|
||||||
export { viewportUtils };
|
export { viewportUtils };
|
||||||
|
|||||||
@ -16,9 +16,10 @@ Package.onUse(function(api) {
|
|||||||
api.use('validatejs');
|
api.use('validatejs');
|
||||||
|
|
||||||
// Our custom packages
|
// Our custom packages
|
||||||
api.use('design');
|
api.use('ohif:design');
|
||||||
api.use('ohif:core');
|
api.use('ohif:core');
|
||||||
api.use('ohif:cornerstone');
|
api.use('ohif:cornerstone');
|
||||||
|
api.use('ohif:log');
|
||||||
|
|
||||||
const assets = [
|
const assets = [
|
||||||
'assets/icons.svg',
|
'assets/icons.svg',
|
||||||
@ -137,7 +138,6 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.styl', 'client');
|
api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.styl', 'client');
|
||||||
|
|
||||||
api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.html', 'client');
|
api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.html', 'client');
|
||||||
api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.js', 'client');
|
|
||||||
api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.styl', 'client');
|
api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.styl', 'client');
|
||||||
|
|
||||||
api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.html', 'client');
|
api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.html', 'client');
|
||||||
@ -178,6 +178,10 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.js', 'client');
|
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.js', 'client');
|
||||||
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.styl', 'client');
|
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.styl', 'client');
|
||||||
|
|
||||||
|
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.html', 'client');
|
||||||
|
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.js', 'client');
|
||||||
|
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.styl', 'client');
|
||||||
|
|
||||||
api.addFiles('client/components/viewer/displaySetNavigation/displaySetNavigation.html', 'client');
|
api.addFiles('client/components/viewer/displaySetNavigation/displaySetNavigation.html', 'client');
|
||||||
api.addFiles('client/components/viewer/displaySetNavigation/displaySetNavigation.js', 'client');
|
api.addFiles('client/components/viewer/displaySetNavigation/displaySetNavigation.js', 'client');
|
||||||
|
|
||||||
@ -197,105 +201,13 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('client/components/viewer/studyTimepointBrowser/studyTimepointStudy.styl', 'client');
|
api.addFiles('client/components/viewer/studyTimepointBrowser/studyTimepointStudy.styl', 'client');
|
||||||
api.addFiles('client/components/viewer/studyTimepointBrowser/studyTimepointStudy.js', 'client');
|
api.addFiles('client/components/viewer/studyTimepointBrowser/studyTimepointStudy.js', 'client');
|
||||||
|
|
||||||
|
|
||||||
// Library functions
|
// Library functions
|
||||||
api.addFiles('client/lib/layoutManager.js', 'client');
|
|
||||||
api.addFiles('client/lib/createStacks.js', 'client');
|
|
||||||
api.addFiles('client/lib/getImageId.js', 'client');
|
|
||||||
api.addFiles('client/lib/getWADORSImageId.js', 'client');
|
|
||||||
api.addFiles('client/lib/metaDataProvider.js', 'client');
|
|
||||||
api.addFiles('client/lib/sortStudy.js', 'client');
|
|
||||||
api.addFiles('client/lib/toolManager.js', 'client');
|
|
||||||
api.addFiles('client/lib/enablePrefetchOnElement.js', 'client');
|
|
||||||
api.addFiles('client/lib/displayReferenceLines.js', 'client');
|
|
||||||
api.addFiles('client/lib/toggleDialog.js', 'client');
|
|
||||||
api.addFiles('client/lib/setActiveViewport.js', 'client');
|
|
||||||
api.addFiles('client/lib/switchToImageByIndex.js', 'client');
|
|
||||||
api.addFiles('client/lib/switchToImageRelative.js', 'client');
|
|
||||||
api.addFiles('client/lib/enableHotkeys.js', 'client');
|
|
||||||
api.addFiles('client/lib/viewportFunctions.js', 'client');
|
|
||||||
api.addFiles('client/lib/WLPresets.js', 'client');
|
|
||||||
api.addFiles('client/lib/resizeViewportElements.js', 'client');
|
|
||||||
api.addFiles('client/lib/setFocusToActiveViewport.js', 'client');
|
|
||||||
api.addFiles('client/lib/updateAllViewports.js', 'client');
|
|
||||||
api.addFiles('client/lib/stackImagePositionOffsetSynchronizer.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/lib/instanceClassSpecificViewport.js', 'client');
|
|
||||||
api.addFiles('client/lib/setMammogramViewportAlignment.js', 'client');
|
|
||||||
api.addFiles('client/lib/isImage.js', 'client');
|
|
||||||
api.addFiles('client/lib/sopClassDictionary.js', 'client');
|
|
||||||
api.addFiles('client/lib/debugReactivity.js', 'client');
|
|
||||||
api.addFiles('client/lib/unloadHandlers.js', 'client');
|
|
||||||
|
|
||||||
api.export('resizeViewportElements', 'client');
|
|
||||||
api.export('handleResize', 'client');
|
|
||||||
api.export('enableHotkeys', 'client');
|
|
||||||
api.export('enablePrefetchOnElement', 'client');
|
|
||||||
api.export('displayReferenceLines', 'client');
|
|
||||||
api.export('setActiveViewport', 'client');
|
|
||||||
api.export('createStacks', 'client');
|
|
||||||
api.export('getImageId', 'client');
|
|
||||||
api.export('getWADORSImageId', 'client');
|
|
||||||
api.export('metaDataProvider', 'client');
|
|
||||||
api.export('sortStudy', 'client');
|
|
||||||
api.export('updateOrientationMarkers', 'client');
|
|
||||||
api.export('setFocusToActiveViewport', 'client');
|
|
||||||
api.export('updateAllViewports', 'client');
|
|
||||||
api.export('queryStudies', 'client');
|
|
||||||
api.export('getNumberOfFilesInStudy', 'client');
|
|
||||||
api.export('importStudies', 'client');
|
|
||||||
api.export('getActiveViewportElement', 'client');
|
|
||||||
api.export('getInstanceClassDefaultViewport', 'client');
|
|
||||||
api.export('showConfirmDialog', 'client');
|
|
||||||
api.export('applyWLPreset', 'client');
|
|
||||||
api.export('toggleDialog', 'client');
|
|
||||||
api.export('isImage', 'client');
|
|
||||||
api.export('sopClassDictionary', 'client');
|
|
||||||
api.export('addMetaData', 'client');
|
|
||||||
api.export('hasMultipleFrames', 'client');
|
|
||||||
api.export('isStackScrollLinkingDisabled')
|
|
||||||
|
|
||||||
// Viewer management objects
|
|
||||||
api.export('toolManager', 'client');
|
|
||||||
api.export('LayoutManager', 'client');
|
|
||||||
|
|
||||||
// Collections
|
// Collections
|
||||||
api.export('ViewerStudies', 'client');
|
api.export('ViewerStudies', 'client');
|
||||||
|
|
||||||
// UI Helpers
|
api.export('dialogPolyfill', 'client');
|
||||||
api.addFiles([
|
|
||||||
'client/lib/helpers/formatDA.js',
|
|
||||||
'client/lib/helpers/formatJSDate.js',
|
|
||||||
'client/lib/helpers/jsDateFromNow.js',
|
|
||||||
'client/lib/helpers/formatNumberPrecision.js',
|
|
||||||
'client/lib/helpers/formatTM.js',
|
|
||||||
'client/lib/helpers/inc.js',
|
|
||||||
'client/lib/helpers/isDisplaySetActive.js',
|
|
||||||
'client/lib/helpers/getUsername.js',
|
|
||||||
'client/lib/helpers/capitalizeFirstLetter.js',
|
|
||||||
'client/lib/helpers/objectToPairs.js',
|
|
||||||
'client/lib/helpers/objectEach.js',
|
|
||||||
'client/lib/helpers/ifTypeIs.js',
|
|
||||||
'client/lib/helpers/prettyPrintStringify.js',
|
|
||||||
'client/lib/helpers/sorting.js',
|
|
||||||
'client/lib/helpers/studyThumbnails.js',
|
|
||||||
'client/lib/helpers/formatPN.js'
|
|
||||||
], 'client');
|
|
||||||
api.export('formatPN', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/lib/helpers/isTouchDevice.js', 'client');
|
api.mainModule('main.js', '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.export('flipV', 'client');
|
|
||||||
api.export('flipH', 'client');
|
|
||||||
api.export('rotateR', 'client');
|
|
||||||
api.export('rotateL', 'client');
|
|
||||||
api.export('link', 'client');
|
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user