Merging toolManager, enablePrefetchOnElement and imageViewerViewport...
This commit is contained in:
parent
068192e035
commit
00656ef943
@ -1,4 +1,8 @@
|
|||||||
|
import { TypeSafeCollection } from './lib/classes/TypeSafeCollection';
|
||||||
|
|
||||||
|
Studies = new TypeSafeCollection();
|
||||||
|
|
||||||
ViewerStudies = new Meteor.Collection(null);
|
ViewerStudies = new Meteor.Collection(null);
|
||||||
ViewerStudies._debugName = 'ViewerStudies';
|
ViewerStudies._debugName = 'ViewerStudies';
|
||||||
|
|
||||||
Meteor.subscribe('studyImportStatus');
|
Meteor.subscribe('studyImportStatus');
|
||||||
|
|||||||
@ -1,6 +1,23 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Tracker } from 'meteor/tracker';
|
||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { Random } from 'meteor/random';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
|
// OHIF Modules
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
// Local Modules
|
||||||
|
import { StackManager } from '../../../lib/StackManager';
|
||||||
|
import { setActiveViewport } from '../../../lib/setActiveViewport';
|
||||||
|
import { imageViewerViewportData } from '../../../lib/imageViewerViewportData';
|
||||||
|
import { updateCrosshairsSynchronizer } from '../../../lib/updateCrosshairsSynchronizer';
|
||||||
|
import { toolManager } from '../../../lib/toolManager';
|
||||||
|
import { updateOrientationMarkers } from '../../../lib/updateOrientationMarkers';
|
||||||
|
import { getInstanceClassDefaultViewport } from '../../../lib/instanceClassSpecificViewport';
|
||||||
|
import { updateMetaData } from '../../../lib/metaDataProvider';
|
||||||
|
import { OHIFError } from '../../../lib/classes/OHIFError';
|
||||||
|
|
||||||
var allCornerstoneEvents = 'CornerstoneToolsMouseDown CornerstoneToolsMouseDownActivate ' +
|
const allCornerstoneEvents = 'CornerstoneToolsMouseDown CornerstoneToolsMouseDownActivate ' +
|
||||||
'CornerstoneToolsMouseClick CornerstoneToolsMouseDrag CornerstoneToolsMouseUp ' +
|
'CornerstoneToolsMouseClick CornerstoneToolsMouseDrag CornerstoneToolsMouseUp ' +
|
||||||
'CornerstoneToolsMouseWheel CornerstoneToolsTap CornerstoneToolsTouchPress ' +
|
'CornerstoneToolsMouseWheel CornerstoneToolsTap CornerstoneToolsTouchPress ' +
|
||||||
'CornerstoneToolsTouchStart CornerstoneToolsTouchStartActive ' +
|
'CornerstoneToolsTouchStart CornerstoneToolsTouchStartActive ' +
|
||||||
@ -11,7 +28,7 @@ var allCornerstoneEvents = 'CornerstoneToolsMouseDown CornerstoneToolsMouseDownA
|
|||||||
*
|
*
|
||||||
* @param data {object} Object containing the study, series, and viewport element to be used
|
* @param data {object} Object containing the study, series, and viewport element to be used
|
||||||
*/
|
*/
|
||||||
function loadDisplaySetIntoViewport(data, templateData) {
|
const loadDisplaySetIntoViewport = (data, templateData) => {
|
||||||
OHIF.log.info('imageViewerViewport loadDisplaySetIntoViewport');
|
OHIF.log.info('imageViewerViewport loadDisplaySetIntoViewport');
|
||||||
|
|
||||||
// Make sure we have all the data required to render the series
|
// Make sure we have all the data required to render the series
|
||||||
@ -25,7 +42,7 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
const element = data.element;
|
const element = data.element;
|
||||||
const viewportIndex = $('.imageViewerViewport').index(element);
|
const viewportIndex = $('.imageViewerViewport').index(element);
|
||||||
|
|
||||||
const layoutManager = window.layoutManager;
|
const layoutManager = OHIF.viewerbase.layoutManager;
|
||||||
layoutManager.viewportData = layoutManager.viewportData || {};
|
layoutManager.viewportData = layoutManager.viewportData || {};
|
||||||
layoutManager.viewportData[viewportIndex] = layoutManager.viewportData[viewportIndex] || {};
|
layoutManager.viewportData[viewportIndex] = layoutManager.viewportData[viewportIndex] || {};
|
||||||
layoutManager.viewportData[viewportIndex].viewportIndex = viewportIndex;
|
layoutManager.viewportData[viewportIndex].viewportIndex = viewportIndex;
|
||||||
@ -45,46 +62,34 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
ViewerData[contentId].loadedSeriesData[viewportIndex] = {};
|
ViewerData[contentId].loadedSeriesData[viewportIndex] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an empty array to populate with image IDs
|
|
||||||
const imageIds = [];
|
|
||||||
|
|
||||||
// Loop through the current series and add metadata to the
|
|
||||||
// Cornerstone meta data provider. This will be used to fill information
|
|
||||||
// into the viewport overlays, and to calculate reference lines and orientation markers
|
|
||||||
const displaySet = data.displaySet;
|
const displaySet = data.displaySet;
|
||||||
const numImages = displaySet.images.length;
|
|
||||||
let imageId;
|
|
||||||
|
|
||||||
displaySet.images.forEach((image, imageIndex) => {
|
// Get stack from Stack Manager
|
||||||
const metaData = {
|
const displaySetStack = StackManager.findStack(displaySet.displaySetInstanceUid);
|
||||||
instance: image,
|
|
||||||
series: displaySet, // TODO: Check this
|
|
||||||
study: data.study,
|
|
||||||
numImages: numImages,
|
|
||||||
imageIndex: imageIndex + 1
|
|
||||||
};
|
|
||||||
|
|
||||||
const numFrames = image.numFrames;
|
// If is a clip, updates the global FPS for cine dialog
|
||||||
if (numFrames > 1) {
|
if (displaySetStack && displaySetStack.isClip === true && displaySetStack.frameRate) {
|
||||||
OHIF.log.info('Multiframe image detected');
|
// Sets the global variable
|
||||||
for (var i = 0; i < numFrames; i++) {
|
OHIF.viewer.cine.framesPerSecond = parseFloat(displaySetStack.frameRate);
|
||||||
metaData.frame = i;
|
// Update the cine dialog FPS
|
||||||
imageId = getImageId(image, i);
|
Session.set('UpdateCINE', Random.id());
|
||||||
imageIds.push(imageId);
|
}
|
||||||
addMetaData(imageId, metaData);
|
|
||||||
}
|
// Array with image IDs
|
||||||
}
|
let imageIds = [];
|
||||||
else {
|
// Make sure if the stack is already loaded in the stack manager, otherwise create it
|
||||||
imageId = getImageId(image);
|
if(!displaySetStack || !displaySetStack.imageIds) {
|
||||||
imageIds.push(imageId);
|
imageIds = StackManager.makeAndAddStack(data.study, displaySet);
|
||||||
addMetaData(imageId, metaData);
|
}
|
||||||
}
|
else {
|
||||||
});
|
imageIds = displaySetStack.imageIds;
|
||||||
|
}
|
||||||
|
|
||||||
// Define the current image stack using the newly created image IDs
|
// Define the current image stack using the newly created image IDs
|
||||||
const stack = {
|
const stack = {
|
||||||
currentImageIdIndex: data.currentImageIdIndex || 0,
|
currentImageIdIndex: data.currentImageIdIndex || 0,
|
||||||
imageIds: imageIds
|
imageIds: imageIds,
|
||||||
|
displaySetInstanceUid: data.displaySetInstanceUid
|
||||||
};
|
};
|
||||||
|
|
||||||
// If is a clip, updates the global FPS for cine dialog
|
// If is a clip, updates the global FPS for cine dialog
|
||||||
@ -96,7 +101,7 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the current image ID for the stack that will be rendered
|
// Get the current image ID for the stack that will be rendered
|
||||||
imageId = imageIds[stack.currentImageIdIndex];
|
const imageId = imageIds[stack.currentImageIdIndex];
|
||||||
|
|
||||||
// Save the current image ID inside the template data so it can be
|
// Save the current image ID inside the template data so it can be
|
||||||
// retrieved from the template helpers
|
// retrieved from the template helpers
|
||||||
@ -140,8 +145,33 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
viewportIndex
|
viewportIndex
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle the case where the imageId isn't loaded correctly and the
|
||||||
|
// imagePromise returns undefined
|
||||||
|
// To test, uncomment the next line
|
||||||
|
// data.imageId = 'AfileThatDoesntWork'; // For testing only!
|
||||||
|
|
||||||
|
let imagePromise;
|
||||||
|
try {
|
||||||
|
imagePromise = cornerstone.loadAndCacheImage(imageId);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
if (!imagePromise) {
|
||||||
|
errorLoadingHandler(element, imageId, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadAndCacheImage configurable callbacks
|
||||||
|
const callbacks = imageViewerViewportData.callbacks;
|
||||||
|
|
||||||
|
// Check if it has before loadAndCacheImage callback
|
||||||
|
if(typeof callbacks.before === 'function') {
|
||||||
|
OHIF.log.info('imageViewerViewport before loadAndCacheImage callback');
|
||||||
|
callbacks.before(imagePromise, templateData);
|
||||||
|
}
|
||||||
|
|
||||||
// Start loading the image.
|
// Start loading the image.
|
||||||
cornerstone.loadAndCacheImage(imageId).then(image => {
|
imagePromise.then(image => {
|
||||||
let enabledElement;
|
let enabledElement;
|
||||||
try {
|
try {
|
||||||
enabledElement = cornerstone.getEnabledElement(element);
|
enabledElement = cornerstone.getEnabledElement(element);
|
||||||
@ -181,8 +211,7 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
|
|
||||||
// Resize the canvas to fit the current viewport element size.
|
// Resize the canvas to fit the current viewport element size.
|
||||||
cornerstone.resize(element, false);
|
cornerstone.resize(element, false);
|
||||||
}
|
} else if (data.viewport) {
|
||||||
else if (data.viewport) {
|
|
||||||
// If there is a saved object containing Cornerstone viewport data
|
// If there is a saved object containing Cornerstone viewport data
|
||||||
// (e.g. scale, invert, window settings) in the input data, apply it now.
|
// (e.g. scale, invert, window settings) in the input data, apply it now.
|
||||||
cornerstone.displayImage(element, image, data.viewport);
|
cornerstone.displayImage(element, image, data.viewport);
|
||||||
@ -190,8 +219,7 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
// Resize the canvas to fit the current viewport element size. Fit the displayed
|
// Resize the canvas to fit the current viewport element size. Fit the displayed
|
||||||
// image to the canvas dimensions.
|
// image to the canvas dimensions.
|
||||||
cornerstone.resize(element, true);
|
cornerstone.resize(element, true);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// If no saved viewport settings or modality-specific settings exists,
|
// If no saved viewport settings or modality-specific settings exists,
|
||||||
// display the loaded image in the viewport element with no loaded viewport
|
// display the loaded image in the viewport element with no loaded viewport
|
||||||
// settings.
|
// settings.
|
||||||
@ -264,11 +292,11 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
|
|
||||||
// Define a function to run whenever the Cornerstone viewport is rendered
|
// Define a function to run whenever the Cornerstone viewport is rendered
|
||||||
// (e.g. following a change of window or zoom)
|
// (e.g. following a change of window or zoom)
|
||||||
const onImageRendered = () => {
|
const onImageRendered = (event, eventData) => {
|
||||||
OHIF.log.info('imageViewerViewport onImageRendered');
|
OHIF.log.info('imageViewerViewport onImageRendered');
|
||||||
|
|
||||||
if (!layoutManager.viewportData[viewportIndex]) {
|
if (!layoutManager.viewportData[viewportIndex]) {
|
||||||
OHIF.log.warn("onImageRendered: LayoutManager has no viewport data for this viewport index?: " + viewportIndex);
|
OHIF.log.warn(`onImageRendered: LayoutManager has no viewport data for this viewport index?: ${viewportIndex}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use Session to trigger reactive updates in the viewportOverlay helper functions
|
// Use Session to trigger reactive updates in the viewportOverlay helper functions
|
||||||
@ -281,6 +309,12 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
layoutManager.viewportData[viewportIndex].viewport = viewport;
|
layoutManager.viewportData[viewportIndex].viewport = viewport;
|
||||||
ViewerData[contentId].loadedSeriesData[viewportIndex].viewport = viewport;
|
ViewerData[contentId].loadedSeriesData[viewportIndex].viewport = viewport;
|
||||||
Session.set('ViewerData', ViewerData);
|
Session.set('ViewerData', ViewerData);
|
||||||
|
|
||||||
|
// Check if it has onImageRendered loadAndCacheImage callback
|
||||||
|
if(typeof callbacks.onImageRendered === 'function') {
|
||||||
|
OHIF.log.info('imageViewerViewport onImageRendered callback');
|
||||||
|
callbacks.onImageRendered(event, eventData, viewportIndex, templateData);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Attach the onImageRendered callback to the CornerstoneImageRendered event
|
// Attach the onImageRendered callback to the CornerstoneImageRendered event
|
||||||
@ -292,10 +326,10 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
|
|
||||||
// Define a function to run whenever the Cornerstone viewport changes images
|
// Define a function to run whenever the Cornerstone viewport changes images
|
||||||
// (e.g. during scrolling)
|
// (e.g. during scrolling)
|
||||||
const onNewImage = (e, eventData) => {
|
const onNewImage = (event, eventData) => {
|
||||||
OHIF.log.info('imageViewerViewport onNewImage');
|
OHIF.log.info('imageViewerViewport onNewImage');
|
||||||
|
|
||||||
// Update the metaData for missing fields of the images in stack
|
// Update the metaData for missing fields
|
||||||
updateMetaData(eventData.enabledElement.image);
|
updateMetaData(eventData.enabledElement.image);
|
||||||
|
|
||||||
// Update the templateData with the new imageId
|
// Update the templateData with the new imageId
|
||||||
@ -305,7 +339,7 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
layoutManager.viewportData[viewportIndex].imageId = eventData.enabledElement.image.imageId;
|
layoutManager.viewportData[viewportIndex].imageId = eventData.enabledElement.image.imageId;
|
||||||
|
|
||||||
// Get the element and stack data
|
// Get the element and stack data
|
||||||
const element = e.target;
|
const element = event.target;
|
||||||
const toolData = cornerstoneTools.getToolState(element, 'stack');
|
const toolData = cornerstoneTools.getToolState(element, 'stack');
|
||||||
if (!toolData || !toolData.data || !toolData.data.length) {
|
if (!toolData || !toolData.data || !toolData.data.length) {
|
||||||
return;
|
return;
|
||||||
@ -324,6 +358,12 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
ViewerData[contentId].loadedSeriesData[viewportIndex].currentImageIdIndex = imageIdIndex;
|
ViewerData[contentId].loadedSeriesData[viewportIndex].currentImageIdIndex = imageIdIndex;
|
||||||
Session.set('ViewerData', ViewerData);
|
Session.set('ViewerData', ViewerData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if it has onNewImage loadAndCacheImage callback
|
||||||
|
if(typeof callbacks.onNewImage === 'function') {
|
||||||
|
OHIF.log.info('imageViewerViewport onNewImage callback');
|
||||||
|
callbacks.onNewImage(event, eventData, viewportIndex, templateData);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Attach the onNewImage callback to the CornerstoneNewImage event
|
// Attach the onNewImage callback to the CornerstoneNewImage event
|
||||||
@ -333,10 +373,12 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
// Set a random value for the Session variable in order to trigger an overlay update
|
// Set a random value for the Session variable in order to trigger an overlay update
|
||||||
Session.set('CornerstoneNewImage' + viewportIndex, Random.id());
|
Session.set('CornerstoneNewImage' + viewportIndex, Random.id());
|
||||||
|
|
||||||
function onStackScroll(e, eventData) {
|
const onStackScroll = (e, eventData) => {
|
||||||
|
OHIF.log.info('imageViewerViewport onStackScroll');
|
||||||
|
|
||||||
// Update the imageSlider value
|
// Update the imageSlider value
|
||||||
Session.set('CornerstoneNewImage' + viewportIndex, Random.id());
|
Session.set('CornerstoneNewImage' + viewportIndex, Random.id());
|
||||||
}
|
};
|
||||||
|
|
||||||
$element.off('CornerstoneStackScroll', onStackScroll);
|
$element.off('CornerstoneStackScroll', onStackScroll);
|
||||||
if (stack.imageIds.length > 1) {
|
if (stack.imageIds.length > 1) {
|
||||||
@ -346,7 +388,7 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
// Define a function to trigger an event whenever a new viewport is being used
|
// Define a function to trigger an event whenever a new viewport is being used
|
||||||
// This is used to update the value of the "active viewport", when the user interacts
|
// This is used to update the value of the "active viewport", when the user interacts
|
||||||
// with a new viewport element
|
// with a new viewport element
|
||||||
const sendActivationTrigger = (e, eventData) => {
|
const sendActivationTrigger = (event, eventData) => {
|
||||||
// Check if the current active viewport in the Meteor Session
|
// Check if the current active viewport in the Meteor Session
|
||||||
// Is the same as the viewport in which the activation event was fired.
|
// Is the same as the viewport in which the activation event was fired.
|
||||||
// If it was, no changes are necessary, so stop here.
|
// If it was, no changes are necessary, so stop here.
|
||||||
@ -363,14 +405,14 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
|
|
||||||
OHIF.log.info('imageViewerViewport sendActivationTrigger');
|
OHIF.log.info('imageViewerViewport sendActivationTrigger');
|
||||||
|
|
||||||
// Otherwise, trigger an 'ActivateViewport' event to be handled by the Template event
|
// Otherwise, trigger an 'OHIFActivateViewport' event to be handled by the Template event
|
||||||
// handler
|
// handler
|
||||||
eventData.viewportIndex = viewportIndex;
|
eventData.viewportIndex = viewportIndex;
|
||||||
const customEvent = $.Event('ActivateViewport', eventData);
|
const customEvent = $.Event('OHIFActivateViewport', eventData);
|
||||||
|
|
||||||
// Need to overwrite the type set in the original event
|
// Need to overwrite the type set in the original event
|
||||||
customEvent.type = 'ActivateViewport';
|
customEvent.type = 'OHIFActivateViewport';
|
||||||
$(e.target).trigger(customEvent, eventData);
|
$(event.target).trigger(customEvent, eventData);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Attach the sendActivationTrigger function to all of the Cornerstone interaction events
|
// Attach the sendActivationTrigger function to all of the Cornerstone interaction events
|
||||||
@ -379,15 +421,27 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
|
|
||||||
ViewerData[contentId].loadedSeriesData = layoutManager.viewportData;
|
ViewerData[contentId].loadedSeriesData = layoutManager.viewportData;
|
||||||
|
|
||||||
// Check if image plane (orientation / loction) data is present for the current image
|
// Check if image plane (orientation / location) data is present for the current image
|
||||||
const imagePlane = cornerstoneTools.metaData.get('imagePlane', image.imageId);
|
const imagePlane = cornerstoneTools.metaData.get('imagePlane', image.imageId);
|
||||||
|
if (imagePlane && imagePlane.frameOfReferenceUID) {
|
||||||
|
|
||||||
// If it is, and reference lines are enabled, add this element to the global synchronizer
|
// If it is, add this element to the global synchronizer...
|
||||||
// that is used for updating reference lines, and enable reference lines for this viewport.
|
|
||||||
if (OHIF.viewer.refLinesEnabled && imagePlane && imagePlane.frameOfReferenceUID) {
|
|
||||||
OHIF.viewer.updateImageSynchronizer.add(element);
|
OHIF.viewer.updateImageSynchronizer.add(element);
|
||||||
|
if (OHIF.viewer.refLinesEnabled) {
|
||||||
|
// ... and if reference lines are globally enabled, let cornerstoneTools know.
|
||||||
|
cornerstoneTools.referenceLines.tool.enable(element, OHIF.viewer.updateImageSynchronizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the crosshairs tool is active, update the synchronizer
|
||||||
|
// that is used for its synchronized viewport updating.
|
||||||
|
// This is necessary if this new image shares a frame of reference
|
||||||
|
// with currently displayed images
|
||||||
|
if (activeTool === 'crosshairs') {
|
||||||
|
updateCrosshairsSynchronizer(imagePlane.frameOfReferenceUID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Set the active viewport based on the Session variable
|
// Set the active viewport based on the Session variable
|
||||||
// This is done to ensure that the active element has the current
|
// This is done to ensure that the active element has the current
|
||||||
// focus, so that keyboard events are triggered.
|
// focus, so that keyboard events are triggered.
|
||||||
@ -402,11 +456,17 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
|
|
||||||
// Update the LayoutManagerUpdated session key
|
// Update the LayoutManagerUpdated session key
|
||||||
layoutManager.updateSession();
|
layoutManager.updateSession();
|
||||||
}, function(error) {
|
|
||||||
|
// Check if it has after loadAndCacheImage callback
|
||||||
|
if(typeof callbacks.after === 'function') {
|
||||||
|
OHIF.log.info('imageViewerViewport after callback');
|
||||||
|
callbacks.after(image, templateData, element);
|
||||||
|
}
|
||||||
|
}, error => {
|
||||||
// If something goes wrong while loading the image, fire the error handler.
|
// If something goes wrong while loading the image, fire the error handler.
|
||||||
errorLoadingHandler(element, imageId, error);
|
errorLoadingHandler(element, imageId, error);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function sets the display set for the study and calls LoadDisplaySetIntoViewport function
|
* This function sets the display set for the study and calls LoadDisplaySetIntoViewport function
|
||||||
@ -416,13 +476,13 @@ function loadDisplaySetIntoViewport(data, templateData) {
|
|||||||
* @param templateData currentData of Template
|
* @param templateData currentData of Template
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function setDisplaySet(data, displaySetInstanceUid, templateData) {
|
const setDisplaySet = (data, displaySetInstanceUid, templateData) => {
|
||||||
var study = data.study;
|
const study = data.study;
|
||||||
if (!study || !study.displaySets) {
|
if (!study || !study.series) {
|
||||||
throw 'Study does not exist or has no display sets';
|
throw new OHIFError('Study does not exist or has no display sets');
|
||||||
}
|
}
|
||||||
|
|
||||||
study.displaySets.every(displaySet => {
|
study.series.every(displaySet => {
|
||||||
if (displaySet.displaySetInstanceUid === displaySetInstanceUid) {
|
if (displaySet.displaySetInstanceUid === displaySetInstanceUid) {
|
||||||
data.displaySet = displaySet;
|
data.displaySet = displaySet;
|
||||||
return false;
|
return false;
|
||||||
@ -433,12 +493,12 @@ function setDisplaySet(data, displaySetInstanceUid, templateData) {
|
|||||||
|
|
||||||
// If we didn't find anything, stop here
|
// If we didn't find anything, stop here
|
||||||
if (!data.displaySet) {
|
if (!data.displaySet) {
|
||||||
throw 'Display set not found in specified study!';
|
throw new OHIFError('Display set not found in specified study!');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, load pass the data object into loadSeriesIntoViewport
|
// Otherwise, load pass the data object into loadSeriesIntoViewport
|
||||||
loadDisplaySetIntoViewport(data, templateData);
|
loadDisplaySetIntoViewport(data, templateData);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function searches an object to return the keys that contain a specific value
|
* This function searches an object to return the keys that contain a specific value
|
||||||
@ -448,10 +508,10 @@ function setDisplaySet(data, displaySetInstanceUid, templateData) {
|
|||||||
*
|
*
|
||||||
* @returns {array} The keys for which the object has the specified value
|
* @returns {array} The keys for which the object has the specified value
|
||||||
*/
|
*/
|
||||||
function getKeysByValue(object, value) {
|
const getKeysByValue = (object, value) => {
|
||||||
// http://stackoverflow.com/questions/9907419/javascript-object-get-key-by-value
|
// http://stackoverflow.com/questions/9907419/javascript-object-get-key-by-value
|
||||||
return Object.keys(object).filter(key => object[key] === value);
|
return Object.keys(object).filter(key => object[key] === value);
|
||||||
}
|
};
|
||||||
|
|
||||||
Meteor.startup(function() {
|
Meteor.startup(function() {
|
||||||
// On Meteor startup, define the global objects used to store loading imageIds
|
// On Meteor startup, define the global objects used to store loading imageIds
|
||||||
@ -480,11 +540,11 @@ Meteor.startup(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Template.imageViewerViewport.onRendered(function() {
|
Template.imageViewerViewport.onRendered(function() {
|
||||||
var templateData = Template.currentData();
|
const templateData = Template.currentData();
|
||||||
OHIF.log.info('imageViewerViewport onRendered');
|
OHIF.log.info('imageViewerViewport onRendered');
|
||||||
|
|
||||||
// When the imageViewerViewport template is rendered
|
// When the imageViewerViewport template is rendered
|
||||||
var element = this.find('.imageViewerViewport');
|
const element = this.find('.imageViewerViewport');
|
||||||
this.element = element;
|
this.element = element;
|
||||||
|
|
||||||
// Display the loading indicator for this element
|
// Display the loading indicator for this element
|
||||||
@ -492,32 +552,45 @@ Template.imageViewerViewport.onRendered(function() {
|
|||||||
|
|
||||||
// Get the current active viewport index, if this viewport has the same index,
|
// Get the current active viewport index, if this viewport has the same index,
|
||||||
// add the CSS 'active' class to highlight this viewport.
|
// add the CSS 'active' class to highlight this viewport.
|
||||||
var activeViewport = Session.get('activeViewport');
|
const activeViewport = Session.get('activeViewport');
|
||||||
|
|
||||||
|
let { currentImageIdIndex } = templateData;
|
||||||
|
const { viewport, studyInstanceUid, seriesInstanceUid, renderedCallback, displaySetInstanceUid } = templateData;
|
||||||
|
|
||||||
|
if(!currentImageIdIndex) {
|
||||||
|
currentImageIdIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls extendData function to provide flexibility between systems
|
||||||
|
imageViewerViewportData.extendData(templateData);
|
||||||
|
|
||||||
// Create a data object to pass to the series loading function (loadSeriesIntoViewport)
|
// Create a data object to pass to the series loading function (loadSeriesIntoViewport)
|
||||||
var data = {
|
const data = {
|
||||||
element: element,
|
element,
|
||||||
viewport: this.data.viewport,
|
viewport,
|
||||||
currentImageIdIndex: this.data.currentImageIdIndex,
|
currentImageIdIndex,
|
||||||
displaySetInstanceUid: this.data.displaySetInstanceUid,
|
displaySetInstanceUid,
|
||||||
studyInstanceUid: this.data.studyInstanceUid,
|
studyInstanceUid,
|
||||||
seriesInstanceUid: this.data.seriesInstanceUid,
|
seriesInstanceUid,
|
||||||
renderedCallback: this.data.renderedCallback,
|
renderedCallback,
|
||||||
activeViewport: activeViewport
|
activeViewport
|
||||||
};
|
};
|
||||||
|
|
||||||
// If no displaySetInstanceUid was supplied, display the drag/drop
|
// If no displaySetInstanceUid was supplied, display the drag/drop
|
||||||
// instructions and then stop here since we don't know what to display in the viewport.
|
// instructions and then stop here since we don't know what to display in the viewport.
|
||||||
if (!this.data.displaySetInstanceUid) {
|
if (!displaySetInstanceUid) {
|
||||||
element.classList.add('empty');
|
element.classList.add('empty');
|
||||||
$(element).siblings('.imageViewerLoadingIndicator').css('display', 'none');
|
$(element).siblings('.imageViewerLoadingIndicator').css('display', 'none');
|
||||||
$(element).siblings('.viewportInstructions').show();
|
$(element).siblings('.viewportInstructions').show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO: Reconcile ViewerStudies and Studies Collection.
|
||||||
|
// const study = Studies.findBy({ studyInstanceUid });
|
||||||
|
|
||||||
// Look through the ViewerStudies collection for a
|
// Look through the ViewerStudies collection for a
|
||||||
// study with this studyInstanceUid
|
// study with this studyInstanceUid
|
||||||
var study = ViewerStudies.findOne({
|
const study = ViewerStudies.findOne({
|
||||||
studyInstanceUid: this.data.studyInstanceUid
|
studyInstanceUid: this.data.studyInstanceUid
|
||||||
});
|
});
|
||||||
var displaySetInstanceUid = this.data.displaySetInstanceUid;
|
var displaySetInstanceUid = this.data.displaySetInstanceUid;
|
||||||
@ -531,30 +604,46 @@ Template.imageViewerViewport.onDestroyed(function() {
|
|||||||
|
|
||||||
// When a viewport element is being destroyed
|
// When a viewport element is being destroyed
|
||||||
var element = this.find('.imageViewerViewport');
|
var element = this.find('.imageViewerViewport');
|
||||||
if (!element || !$(element).find('canvas').length) {
|
if (!element || $(element).hasClass('empty') || !$(element).find('canvas').length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable mouse functions
|
||||||
|
cornerstoneTools.mouseInput.disable(element);
|
||||||
|
cornerstoneTools.touchInput.disable(element);
|
||||||
|
cornerstoneTools.mouseWheelInput.disable(element);
|
||||||
|
|
||||||
|
OHIF.viewer.updateImageSynchronizer.remove(element);
|
||||||
|
|
||||||
|
// Clear the stack prefetch data
|
||||||
|
let stackPrefetchData = cornerstoneTools.getToolState(element, 'stackPrefetch');
|
||||||
|
stackPrefetchData = [];
|
||||||
|
cornerstoneTools.stackPrefetch.disable(element);
|
||||||
|
|
||||||
// Try to stop any currently playing clips
|
// Try to stop any currently playing clips
|
||||||
// Otherwise the interval will continuously throw errors
|
// Otherwise the interval will continuously throw errors
|
||||||
try {
|
try {
|
||||||
var enabledElement = cornerstone.getEnabledElement(this.element);
|
const enabledElement = cornerstone.getEnabledElement(element);
|
||||||
if (enabledElement) {
|
if (enabledElement) {
|
||||||
cornerstoneTools.stopClip(this.element);
|
cornerstoneTools.stopClip(element);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
OHIF.log.warn(error);
|
OHIF.log.warn(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger custom Destroy Viewport event
|
||||||
|
// for compatibility with other systems
|
||||||
|
$(element).trigger('OHIFDestroyedViewport');
|
||||||
|
|
||||||
// Disable the viewport element with Cornerstone
|
// Disable the viewport element with Cornerstone
|
||||||
// This also triggers the removal of the element from all available
|
// This also triggers the removal of the element from all available
|
||||||
// synchronizers, such as the one used for reference lines.
|
// synchronizers, such as the one used for reference lines.
|
||||||
cornerstone.disable(this.element);
|
cornerstone.disable(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.imageViewerViewport.events({
|
Template.imageViewerViewport.events({
|
||||||
'ActivateViewport .imageViewerViewport'(event) {
|
'OHIFActivateViewport .imageViewerViewport'(event) {
|
||||||
OHIF.log.info('imageViewerViewport ActivateViewport');
|
OHIF.log.info('imageViewerViewport OHIFActivateViewport');
|
||||||
setActiveViewport(event.currentTarget);
|
setActiveViewport(event.currentTarget);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -567,18 +656,21 @@ Template.imageViewerViewport.events({
|
|||||||
const viewportIndex = $('.imageViewerViewport').index(event.currentTarget);
|
const viewportIndex = $('.imageViewerViewport').index(event.currentTarget);
|
||||||
|
|
||||||
// Enlarge the double clicked viewport
|
// Enlarge the double clicked viewport
|
||||||
|
const layoutManager = OHIF.viewerbase.layoutManager;
|
||||||
layoutManager.toggleEnlargement(viewportIndex);
|
layoutManager.toggleEnlargement(viewportIndex);
|
||||||
|
|
||||||
// Wait for DOM re-rendering and update the active viewport
|
// Wait for DOM re-rendering and update the active viewport
|
||||||
Tracker.afterFlush(() => {
|
Tracker.afterFlush(() => {
|
||||||
|
let viewportIndexToZoom;
|
||||||
// Check if the viewer is zoomed
|
// Check if the viewer is zoomed
|
||||||
if (layoutManager.isZoomed) {
|
if (layoutManager.isZoomed) {
|
||||||
// Set the active viewport as the only one visible
|
// Set the active viewport as the only one visible
|
||||||
setActiveViewport($('.imageViewerViewport')[0]);
|
viewportIndexToZoom = 0;
|
||||||
} else {
|
} else {
|
||||||
// Set the active viewport as the previous zoomed viewport
|
// Set the active viewport as the previous zoomed viewport
|
||||||
setActiveViewport($('.imageViewerViewport').eq(window.layoutManager.zoomedViewportIndex));
|
viewportIndexToZoom = layoutManager.zoomedViewportIndex || 0;
|
||||||
}
|
}
|
||||||
|
setActiveViewport($('.imageViewerViewport').get(viewportIndexToZoom));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,25 +1,42 @@
|
|||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import { StackManager } from './StackManager.js';
|
||||||
|
import { OHIFError } from './classes/OHIFError';
|
||||||
/**
|
/**
|
||||||
* This function enables stack prefetching for a specified element (viewport)
|
* This function enables stack prefetching for a specified element (viewport)
|
||||||
* It first disables any prefetching currently occurring on any other viewports.
|
* It first disables any prefetching currently occurring on any other viewports.
|
||||||
*
|
*
|
||||||
* @param element {node} DOM Node representing the viewport element
|
* @param element
|
||||||
*/
|
*/
|
||||||
enablePrefetchOnElement = function(element) {
|
export function enablePrefetchOnElement(element) {
|
||||||
OHIF.log.info("imageViewerViewport enablePrefetchOnElement");
|
OHIF.log.info('enablePrefetchOnElement');
|
||||||
|
|
||||||
// Loop through all viewports and disable stackPrefetch
|
// Loop through all of the viewports and disable stackPrefetch
|
||||||
$('.imageViewerViewport').each(function() {
|
$('.viewportContainer .imageViewerViewport').each((index, viewportElement) => {
|
||||||
if (!$(this).find('canvas').length) {
|
if ($(viewportElement).find('canvas').length) {
|
||||||
return;
|
cornerstoneTools.stackPrefetch.disable(viewportElement);
|
||||||
}
|
}
|
||||||
cornerstoneTools.stackPrefetch.disable(this);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure there is a stack to fetch
|
if ($(element).find('canvas').length) {
|
||||||
const stack = cornerstoneTools.getToolState(element, 'stack');
|
// If the stack in the active viewport has more than one image,
|
||||||
if (stack && stack.data.length && stack.data[0].imageIds.length > 1) {
|
// enable prefetching for the element
|
||||||
cornerstoneTools.stackPrefetch.enable(element);
|
const cornerstoneStack = cornerstoneTools.getToolState(element, 'stack');
|
||||||
|
if (cornerstoneStack && cornerstoneStack.data.length && cornerstoneStack.data[0].imageIds.length > 1) {
|
||||||
|
|
||||||
|
// Check if this is a clip or not
|
||||||
|
const activeViewportIndex = Session.get('activeViewport');
|
||||||
|
const contentId = Session.get('activeContentId');
|
||||||
|
const displaySetInstanceUid = ViewerData[contentId].loadedSeriesData[activeViewportIndex].displaySetInstanceUid;
|
||||||
|
|
||||||
|
const stack = StackManager.findStack(displaySetInstanceUid);
|
||||||
|
|
||||||
|
if (!stack) {
|
||||||
|
throw new OHIFError(`Requested stack ${displaySetInstanceUid} was not created`);
|
||||||
|
}
|
||||||
|
|
||||||
|
cornerstoneTools.stackPrefetch.enable(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@ -1,13 +1,33 @@
|
|||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { $ } from 'meteor/jquery';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import { getFrameOfReferenceUID } from './getFrameOfReferenceUID';
|
||||||
|
import { updateCrosshairsSynchronizer } from './updateCrosshairsSynchronizer';
|
||||||
|
import { crosshairsSynchronizers } from './crosshairsSynchronizers';
|
||||||
|
|
||||||
let activeTool = 'wwwc';
|
let activeTool = 'wwwc';
|
||||||
let defaultTool = 'wwwc';
|
let defaultTool = 'wwwc';
|
||||||
|
|
||||||
let tools = {};
|
let tools = {};
|
||||||
|
|
||||||
|
let gestures = {
|
||||||
|
zoomTouchPinch: {
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
panMultiTouch: {
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
stackScrollMultiTouch: {
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
doubleTapZoom: {
|
||||||
|
enabled: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let toolDefaultStates = {
|
let toolDefaultStates = {
|
||||||
activate: [],
|
activate: [],
|
||||||
deactivate: ['length', 'angle', 'annotate', 'ellipticalRoi', 'rectangleRoi'],
|
deactivate: ['length', 'angle', 'annotate', 'ellipticalRoi', 'rectangleRoi', 'textMarker'],
|
||||||
enable: [],
|
enable: [],
|
||||||
disable: [],
|
disable: [],
|
||||||
disabledToolButtons: [],
|
disabledToolButtons: [],
|
||||||
@ -21,74 +41,10 @@ let toolDefaultStates = {
|
|||||||
|
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
|
|
||||||
const configureTools = () => {
|
/**
|
||||||
|
* Exported "toolManager" Singleton
|
||||||
// Get Cornerstone Tools
|
*/
|
||||||
const { panMultiTouch, textStyle, toolStyle, toolColors,
|
export const toolManager = {
|
||||||
length, arrowAnnotate, zoom, ellipticalRoi } = cornerstoneTools;
|
|
||||||
|
|
||||||
// Set the configuration for the multitouch pan tool
|
|
||||||
const multiTouchPanConfig = {
|
|
||||||
testPointers: eventData => {
|
|
||||||
return (eventData.numPointers >= 3);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
panMultiTouch.setConfiguration(multiTouchPanConfig);
|
|
||||||
|
|
||||||
// Set text box background color
|
|
||||||
textStyle.setBackgroundColor('transparent');
|
|
||||||
|
|
||||||
// Set the tool font and font size
|
|
||||||
// context.font = "[style] [variant] [weight] [size]/[line height] [font family]";
|
|
||||||
const fontFamily = 'Roboto, OpenSans, HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif';
|
|
||||||
textStyle.setFont('15px ' + fontFamily);
|
|
||||||
|
|
||||||
// Set the tool width
|
|
||||||
toolStyle.setToolWidth(2);
|
|
||||||
|
|
||||||
// Set color for inactive tools
|
|
||||||
toolColors.setToolColor('rgb(255, 255, 0)');
|
|
||||||
|
|
||||||
// Set color for active tools
|
|
||||||
toolColors.setActiveColor('rgb(0, 255, 0)');
|
|
||||||
|
|
||||||
// Set shadow configuration
|
|
||||||
const shadowConfig = toolManager.getToolDefaultStates().shadowConfig;
|
|
||||||
|
|
||||||
// Get some tools config to not override them
|
|
||||||
const lengthConfig = length.getConfiguration();
|
|
||||||
const ellipticalRoiConfig = ellipticalRoi.getConfiguration();
|
|
||||||
|
|
||||||
// Add shadow to length tool
|
|
||||||
length.setConfiguration({
|
|
||||||
...lengthConfig,
|
|
||||||
...shadowConfig,
|
|
||||||
drawHandlesOnHover: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add shadow to length tool
|
|
||||||
ellipticalRoi.setConfiguration({
|
|
||||||
...ellipticalRoiConfig,
|
|
||||||
...shadowConfig
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set the configuration values for the text annotation (Arrow) tool
|
|
||||||
const annotateConfig = {
|
|
||||||
getTextCallback: getAnnotationTextCallback,
|
|
||||||
changeTextCallback: changeAnnotationTextCallback,
|
|
||||||
drawHandles: false,
|
|
||||||
arrowFirst: true
|
|
||||||
};
|
|
||||||
arrowAnnotate.setConfiguration(annotateConfig);
|
|
||||||
|
|
||||||
const zoomConfig = {
|
|
||||||
minScale: 0.05,
|
|
||||||
maxScale: 10
|
|
||||||
};
|
|
||||||
zoom.setConfiguration(zoomConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
toolManager = {
|
|
||||||
init() {
|
init() {
|
||||||
toolManager.addTool('wwwc', {
|
toolManager.addTool('wwwc', {
|
||||||
mouse: cornerstoneTools.wwwc,
|
mouse: cornerstoneTools.wwwc,
|
||||||
@ -144,13 +100,94 @@ toolManager = {
|
|||||||
touch: cornerstoneTools.rotateTouchDrag
|
touch: cornerstoneTools.rotateTouchDrag
|
||||||
});
|
});
|
||||||
|
|
||||||
|
toolManager.addTool('spine', {
|
||||||
|
mouse: cornerstoneTools.textMarker,
|
||||||
|
touch: cornerstoneTools.textMarkerTouch
|
||||||
|
});
|
||||||
|
|
||||||
|
toolManager.addTool('crosshairs', {
|
||||||
|
mouse: cornerstoneTools.crosshairs,
|
||||||
|
touch: cornerstoneTools.crosshairsTouch
|
||||||
|
});
|
||||||
|
|
||||||
if (OHIF.viewer.defaultTool) {
|
if (OHIF.viewer.defaultTool) {
|
||||||
activeTool = OHIF.viewer.defaultTool;
|
activeTool = OHIF.viewer.defaultTool;
|
||||||
}
|
}
|
||||||
|
|
||||||
configureTools();
|
this.configureTools();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
},
|
},
|
||||||
|
configureTools() {
|
||||||
|
// Get Cornerstone Tools
|
||||||
|
const { panMultiTouch, textStyle, toolStyle, toolColors,
|
||||||
|
length, arrowAnnotate, zoom, ellipticalRoi } = cornerstoneTools;
|
||||||
|
|
||||||
|
// Set the configuration for the multitouch pan tool
|
||||||
|
const multiTouchPanConfig = {
|
||||||
|
testPointers: eventData => {
|
||||||
|
return (eventData.numPointers >= 3);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
panMultiTouch.setConfiguration(multiTouchPanConfig);
|
||||||
|
|
||||||
|
// Set text box background color
|
||||||
|
textStyle.setBackgroundColor('transparent');
|
||||||
|
|
||||||
|
// Set the tool font and font size
|
||||||
|
// context.font = "[style] [variant] [weight] [size]/[line height] [font family]";
|
||||||
|
const fontFamily = 'Roboto, OpenSans, HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif';
|
||||||
|
textStyle.setFont('15px ' + fontFamily);
|
||||||
|
|
||||||
|
// Set the tool width
|
||||||
|
toolStyle.setToolWidth(2);
|
||||||
|
|
||||||
|
// Set color for inactive tools
|
||||||
|
toolColors.setToolColor('rgb(255, 255, 0)');
|
||||||
|
|
||||||
|
// Set color for active tools
|
||||||
|
toolColors.setActiveColor('rgb(0, 255, 0)');
|
||||||
|
|
||||||
|
// Set shadow configuration
|
||||||
|
const shadowConfig = toolManager.getToolDefaultStates().shadowConfig;
|
||||||
|
|
||||||
|
// Get some tools config to not override them
|
||||||
|
const lengthConfig = length.getConfiguration();
|
||||||
|
const ellipticalRoiConfig = ellipticalRoi.getConfiguration();
|
||||||
|
|
||||||
|
// Add shadow to length tool
|
||||||
|
length.setConfiguration({
|
||||||
|
...lengthConfig,
|
||||||
|
...shadowConfig,
|
||||||
|
drawHandlesOnHover: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add shadow to length tool
|
||||||
|
ellipticalRoi.setConfiguration({
|
||||||
|
...ellipticalRoiConfig,
|
||||||
|
...shadowConfig
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the configuration values for the text annotation (Arrow) tool
|
||||||
|
const annotateConfig = {
|
||||||
|
getTextCallback: getAnnotationTextCallback,
|
||||||
|
changeTextCallback: changeAnnotationTextCallback,
|
||||||
|
drawHandles: false,
|
||||||
|
arrowFirst: true
|
||||||
|
};
|
||||||
|
arrowAnnotate.setConfiguration(annotateConfig);
|
||||||
|
|
||||||
|
const zoomConfig = {
|
||||||
|
minScale: 0.05,
|
||||||
|
maxScale: 10
|
||||||
|
};
|
||||||
|
zoom.setConfiguration(zoomConfig);
|
||||||
|
},
|
||||||
|
setGestures(newGestures) {
|
||||||
|
gestures = newGestures;
|
||||||
|
},
|
||||||
|
getGestures() {
|
||||||
|
return gestures;
|
||||||
|
},
|
||||||
addTool(name, base) {
|
addTool(name, base) {
|
||||||
tools[name] = base;
|
tools[name] = base;
|
||||||
},
|
},
|
||||||
@ -164,7 +201,7 @@ toolManager = {
|
|||||||
return toolDefaultStates;
|
return toolDefaultStates;
|
||||||
},
|
},
|
||||||
setActiveToolForElement(tool, element) {
|
setActiveToolForElement(tool, element) {
|
||||||
var canvases = $(element).find('canvas');
|
const canvases = $(element).find('canvas');
|
||||||
if (element.classList.contains('empty') || !canvases.length) {
|
if (element.classList.contains('empty') || !canvases.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -177,12 +214,12 @@ toolManager = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable tools based on their default states
|
// Enable tools based on their default states
|
||||||
Object.keys(toolDefaultStates).forEach(function(action) {
|
Object.keys(toolDefaultStates).forEach( action => {
|
||||||
var relevantTools = toolDefaultStates[action];
|
const relevantTools = toolDefaultStates[action];
|
||||||
if (!relevantTools || !relevantTools.length || action === 'disabledToolButtons') {
|
if (!relevantTools || !relevantTools.length || action === 'disabledToolButtons') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
relevantTools.forEach(function(toolType) {
|
relevantTools.forEach( toolType => {
|
||||||
// the currently active tool has already been deactivated and can be skipped
|
// the currently active tool has already been deactivated and can be skipped
|
||||||
if (action === 'deactivate' && toolType === activeTool) {
|
if (action === 'deactivate' && toolType === activeTool) {
|
||||||
return;
|
return;
|
||||||
@ -196,40 +233,75 @@ toolManager = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Get the stack toolData
|
// Get the stack toolData
|
||||||
var toolData = cornerstoneTools.getToolState(element, 'stack');
|
const toolData = cornerstoneTools.getToolState(element, 'stack');
|
||||||
if (!toolData || !toolData.data || !toolData.data.length) {
|
if (!toolData || !toolData.data || !toolData.data.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the imageIds for this element
|
// Get the imageIds for this element
|
||||||
var imageIds = toolData.data[0].imageIds;
|
const imageIds = toolData.data[0].imageIds;
|
||||||
|
|
||||||
// Deactivate all the middle mouse, right click, and scroll wheel tools
|
// Deactivate all the middle mouse, right click, and scroll wheel tools
|
||||||
cornerstoneTools.pan.deactivate(element);
|
cornerstoneTools.pan.deactivate(element);
|
||||||
cornerstoneTools.zoom.deactivate(element);
|
cornerstoneTools.zoom.deactivate(element);
|
||||||
cornerstoneTools.zoomWheel.deactivate(element);
|
cornerstoneTools.zoomWheel.deactivate(element);
|
||||||
cornerstoneTools.stackScrollWheel.deactivate(element);
|
cornerstoneTools.stackScrollWheel.deactivate(element);
|
||||||
|
cornerstoneTools.panMultiTouch.disable(element);
|
||||||
|
cornerstoneTools.zoomTouchPinch.disable(element);
|
||||||
|
cornerstoneTools.stackScrollMultiTouch.disable(element);
|
||||||
|
cornerstoneTools.doubleTapZoom.disable(element);
|
||||||
|
|
||||||
|
// Reactivate the middle mouse and right click tools
|
||||||
|
cornerstoneTools.zoom.activate(element, 4); // zoom is the default tool for right mouse button
|
||||||
|
|
||||||
// Reactivate the relevant scrollwheel tool for this element
|
// Reactivate the relevant scrollwheel tool for this element
|
||||||
|
let multiTouchPanConfig;
|
||||||
if (imageIds.length > 1) {
|
if (imageIds.length > 1) {
|
||||||
// scroll is the default tool for middle mouse wheel for stacks
|
// scroll is the default tool for middle mouse wheel for stacks
|
||||||
cornerstoneTools.stackScrollWheel.activate(element);
|
cornerstoneTools.stackScrollWheel.activate(element);
|
||||||
|
|
||||||
|
if (gestures['stackScrollMultiTouch'].enabled === true) {
|
||||||
|
cornerstoneTools.stackScrollMultiTouch.activate(element); // Three finger scroll
|
||||||
|
}
|
||||||
|
|
||||||
|
multiTouchPanConfig = {
|
||||||
|
testPointers(eventData) {
|
||||||
|
return (eventData.numPointers === 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cornerstoneTools.panMultiTouch.setConfiguration(multiTouchPanConfig);
|
||||||
} else {
|
} else {
|
||||||
// zoom is the default tool for middle mouse wheel for single images (non stacks)
|
// zoom is the default tool for middle mouse wheel for single images (non stacks)
|
||||||
cornerstoneTools.zoomWheel.activate(element);
|
cornerstoneTools.zoomWheel.activate(element);
|
||||||
|
|
||||||
|
multiTouchPanConfig = {
|
||||||
|
testPointers(eventData) {
|
||||||
|
return (eventData.numPointers >= 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cornerstoneTools.panMultiTouch.setConfiguration(multiTouchPanConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This block ensures that the middle mouse and scroll tools keep working
|
// This block ensures that the middle mouse and scroll tools keep working
|
||||||
if (tool === 'pan') {
|
if (tool === 'pan') {
|
||||||
cornerstoneTools.pan.activate(element, 3); // 3 means left mouse button and middle mouse button
|
cornerstoneTools.pan.activate(element, 3); // 3 means left mouse button and middle mouse button
|
||||||
cornerstoneTools.zoom.activate(element, 4); // zoom is the default tool for right mouse button
|
} else if (tool === 'crosshairs') {
|
||||||
|
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
||||||
|
const currentFrameOfReferenceUID = getFrameOfReferenceUID(element);
|
||||||
|
if (currentFrameOfReferenceUID) {
|
||||||
|
updateCrosshairsSynchronizer(currentFrameOfReferenceUID);
|
||||||
|
const synchronizer = crosshairsSynchronizers.synchronizers[currentFrameOfReferenceUID];
|
||||||
|
|
||||||
|
// Activate the chosen tool
|
||||||
|
tools[tool].mouse.activate(element, 1, synchronizer);
|
||||||
|
}
|
||||||
} else if (tool === 'zoom') {
|
} else if (tool === 'zoom') {
|
||||||
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
||||||
cornerstoneTools.zoom.activate(element, 5); // 5 means left mouse button and right mouse button
|
cornerstoneTools.zoom.activate(element, 5); // 5 means left mouse button and right mouse button
|
||||||
} else {
|
} else {
|
||||||
// Reactivate the middle mouse and right click tools
|
// Reactivate the middle mouse and right click tools
|
||||||
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
||||||
cornerstoneTools.zoom.activate(element, 4); // zoom is the default tool for right mouse button
|
|
||||||
|
|
||||||
// Activate the chosen tool
|
// Activate the chosen tool
|
||||||
tools[tool].mouse.activate(element, 1);
|
tools[tool].mouse.activate(element, 1);
|
||||||
@ -239,14 +311,45 @@ toolManager = {
|
|||||||
tools[tool].touch.activate(element);
|
tools[tool].touch.activate(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
cornerstoneTools.zoomTouchPinch.activate(element);
|
if (gestures['zoomTouchPinch'].enabled === true) {
|
||||||
cornerstoneTools.panMultiTouch.activate(element);
|
cornerstoneTools.zoomTouchPinch.activate(element); // Two finger pinch
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gestures['panMultiTouch'].enabled === true) {
|
||||||
|
cornerstoneTools.panMultiTouch.activate(element); // Two or >= Two finger pan
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gestures['doubleTapZoom'].enabled === true) {
|
||||||
|
cornerstoneTools.doubleTapZoom.activate(element);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setActiveTool(tool, elements) {
|
setActiveTool(tool, elements) {
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
toolManager.init();
|
toolManager.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Add textMarkerDialogs template to OHIF's
|
||||||
|
*/
|
||||||
|
const dialog = document.getElementById('textMarkerOptionsDialog');
|
||||||
|
if(dialog) {
|
||||||
|
if (tool === 'spine' && activeTool !== 'spine' && dialog.getAttribute('open') !== 'open') {
|
||||||
|
dialog.show();
|
||||||
|
} else if(activeTool !== 'spine' && dialog.getAttribute("open") === "open") {
|
||||||
|
dialog.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Use Session variables to activate a button and use Helpers like in toolbarSectionButton.js from OHIF’s.
|
||||||
|
*/
|
||||||
|
// Set the div to active for the tool
|
||||||
|
$('.imageViewerButton').removeClass('active');
|
||||||
|
const toolButton = document.getElementById(tool);
|
||||||
|
if (toolButton) {
|
||||||
|
toolButton.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
if (!tool) {
|
if (!tool) {
|
||||||
tool = defaultTool;
|
tool = defaultTool;
|
||||||
}
|
}
|
||||||
@ -277,6 +380,11 @@ toolManager = {
|
|||||||
getDefaultTool() {
|
getDefaultTool() {
|
||||||
return defaultTool;
|
return defaultTool;
|
||||||
},
|
},
|
||||||
|
setConfigureTools(configureTools) {
|
||||||
|
if(typeof configureTools === 'function') {
|
||||||
|
this.configureTools = configureTools;
|
||||||
|
}
|
||||||
|
},
|
||||||
activateCommandButton(button) {
|
activateCommandButton(button) {
|
||||||
const activeCommandButtons = Session.get('ToolManagerActiveCommandButtons') || [];
|
const activeCommandButtons = Session.get('ToolManagerActiveCommandButtons') || [];
|
||||||
|
|
||||||
@ -294,5 +402,4 @@ toolManager = {
|
|||||||
Session.set('ToolManagerActiveCommandButtons', activeCommandButtons);
|
Session.set('ToolManagerActiveCommandButtons', activeCommandButtons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user