Removing duplicated files/functions
This commit is contained in:
parent
2ed38cf6e7
commit
e40649533c
@ -1,58 +0,0 @@
|
||||
/**
|
||||
* Updates the orientation labels on a Cornerstone-enabled Viewport element
|
||||
* when the viewport settings change (e.g. when a horizontal flip or a rotation occurs)
|
||||
*
|
||||
* @param element The DOM element of the Cornerstone viewport
|
||||
*/
|
||||
updateOrientationMarkers = function(element) {
|
||||
// Get the current viewport settings
|
||||
var viewport = cornerstone.getViewport(element);
|
||||
|
||||
var enabledElement = cornerstone.getEnabledElement(element);
|
||||
var imagePlane = cornerstoneTools.metaData.get('imagePlane', enabledElement.image.imageId);
|
||||
|
||||
if (!imagePlane || !imagePlane.rowCosines || !imagePlane.columnCosines) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rowString = cornerstoneTools.orientation.getOrientationString(imagePlane.rowCosines);
|
||||
var columnString = cornerstoneTools.orientation.getOrientationString(imagePlane.columnCosines);
|
||||
var oppositeRowString = cornerstoneTools.orientation.invertOrientationString(rowString);
|
||||
var oppositeColumnString = cornerstoneTools.orientation.invertOrientationString(columnString);
|
||||
|
||||
var markers = {
|
||||
top: oppositeColumnString,
|
||||
left: oppositeRowString
|
||||
};
|
||||
|
||||
// If any vertical or horizontal flips are applied, change the orientation strings ahead of
|
||||
// the rotation applications
|
||||
if (viewport.vflip) {
|
||||
markers.top = cornerstoneTools.orientation.invertOrientationString(markers.top);
|
||||
}
|
||||
|
||||
if (viewport.hflip) {
|
||||
markers.left = cornerstoneTools.orientation.invertOrientationString(markers.left);
|
||||
}
|
||||
|
||||
// Get the viewport orientation marker DOM elements
|
||||
var viewportOrientationMarkers = $(element).siblings('.viewportOrientationMarkers');
|
||||
var topMarker = viewportOrientationMarkers.find('.topMid');
|
||||
var leftMarker = viewportOrientationMarkers.find('.leftMid');
|
||||
|
||||
// Swap the labels accordingly if the viewport has been rotated
|
||||
// This could be done in a more complex way for intermediate rotation values (e.g. 45 degrees)
|
||||
if (viewport.rotation === 90 || viewport.rotation === -270) {
|
||||
topMarker.text(markers.left);
|
||||
leftMarker.text(cornerstoneTools.orientation.invertOrientationString(markers.top));
|
||||
} else if (viewport.rotation === -90 || viewport.rotation === 270) {
|
||||
topMarker.text(cornerstoneTools.orientation.invertOrientationString(markers.left));
|
||||
leftMarker.text(markers.top);
|
||||
} else if (viewport.rotation === 180 || viewport.rotation === -180) {
|
||||
topMarker.text(cornerstoneTools.orientation.invertOrientationString(markers.top));
|
||||
leftMarker.text(cornerstoneTools.orientation.invertOrientationString(markers.left));
|
||||
} else {
|
||||
topMarker.text(markers.top);
|
||||
leftMarker.text(markers.left);
|
||||
}
|
||||
};
|
||||
@ -1,318 +0,0 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Meteor.startup(function() {
|
||||
|
||||
if (!OHIF.viewer) {
|
||||
OHIF.viewer = {};
|
||||
}
|
||||
|
||||
OHIF.viewer.loadIndicatorDelay = 200;
|
||||
OHIF.viewer.defaultTool = 'wwwc';
|
||||
OHIF.viewer.refLinesEnabled = true;
|
||||
OHIF.viewer.isPlaying = {};
|
||||
OHIF.viewer.cine = {
|
||||
framesPerSecond: 24,
|
||||
loop: true
|
||||
};
|
||||
|
||||
OHIF.viewer.defaultHotkeys = {
|
||||
defaultTool: 'ESC',
|
||||
angle: 'A',
|
||||
stackScroll: 'S',
|
||||
pan: 'P',
|
||||
magnify: 'M',
|
||||
scrollDown: 'DOWN',
|
||||
scrollUp: 'UP',
|
||||
nextDisplaySet: 'PAGEDOWN',
|
||||
previousDisplaySet: 'PAGEUP',
|
||||
nextPanel: 'RIGHT',
|
||||
previousPanel: 'LEFT',
|
||||
invert: 'I',
|
||||
flipV: 'V',
|
||||
flipH: 'H',
|
||||
wwwc: 'W',
|
||||
zoom: 'Z',
|
||||
cinePlay: 'SPACE',
|
||||
rotateR: 'R',
|
||||
rotateL: 'L',
|
||||
toggleOverlayTags: 'SHIFT',
|
||||
WLPresetSoftTissue: ['NUMPAD1', '1'],
|
||||
WLPresetLung: ['NUMPAD2', '2'],
|
||||
WLPresetLiver: ['NUMPAD3', '3'],
|
||||
WLPresetBone: ['NUMPAD4', '4'],
|
||||
WLPresetBrain: ['NUMPAD5', '5']
|
||||
};
|
||||
|
||||
// For now
|
||||
OHIF.viewer.hotkeys = OHIF.viewer.defaultHotkeys;
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
// For now
|
||||
OHIF.viewer.wlPresets = OHIF.viewer.defaultWLPresets;
|
||||
|
||||
OHIF.viewer.hotkeyFunctions = {
|
||||
wwwc: function() {
|
||||
toolManager.setActiveTool('wwwc');
|
||||
},
|
||||
zoom: function() {
|
||||
toolManager.setActiveTool('zoom');
|
||||
},
|
||||
angle: function() {
|
||||
toolManager.setActiveTool('angle');
|
||||
},
|
||||
dragProbe: function() {
|
||||
toolManager.setActiveTool('dragProbe');
|
||||
},
|
||||
ellipticalRoi: function() {
|
||||
toolManager.setActiveTool('ellipticalRoi');
|
||||
},
|
||||
magnify: function() {
|
||||
toolManager.setActiveTool('magnify');
|
||||
},
|
||||
annotate: function() {
|
||||
toolManager.setActiveTool('annotate');
|
||||
},
|
||||
stackScroll: function() {
|
||||
toolManager.setActiveTool('stackScroll');
|
||||
},
|
||||
pan: function() {
|
||||
toolManager.setActiveTool('pan');
|
||||
},
|
||||
length: function() {
|
||||
toolManager.setActiveTool('length');
|
||||
},
|
||||
spine: function() {
|
||||
toolManager.setActiveTool('spine');
|
||||
},
|
||||
wwwcRegion: function() {
|
||||
toolManager.setActiveTool('wwwcRegion');
|
||||
},
|
||||
zoomIn: function() {
|
||||
var button = document.getElementById('zoomIn');
|
||||
flashButton(button);
|
||||
zoomIn();
|
||||
},
|
||||
zoomOut: function() {
|
||||
var button = document.getElementById('zoomOut');
|
||||
flashButton(button);
|
||||
zoomOut();
|
||||
},
|
||||
zoomToFit: function() {
|
||||
var button = document.getElementById('zoomToFit');
|
||||
flashButton(button);
|
||||
zoomToFit();
|
||||
},
|
||||
scrollDown: function() {
|
||||
var container = $('.viewportContainer.active');
|
||||
var button = container.find('#nextImage').get(0);
|
||||
|
||||
if (!container.find('.imageViewerViewport').hasClass('empty')) {
|
||||
flashButton(button);
|
||||
switchToImageRelative(1);
|
||||
}
|
||||
},
|
||||
scrollFirstImage: function() {
|
||||
var container = $('.viewportContainer.active');
|
||||
if (!container.find('.imageViewerViewport').hasClass('empty')) {
|
||||
switchToImageByIndex(0);
|
||||
}
|
||||
},
|
||||
scrollLastImage: function() {
|
||||
var container = $('.viewportContainer.active');
|
||||
if (!container.find('.imageViewerViewport').hasClass('empty')) {
|
||||
switchToImageByIndex(-1);
|
||||
}
|
||||
},
|
||||
scrollUp: function() {
|
||||
var container = $('.viewportContainer.active');
|
||||
if (!container.find('.imageViewerViewport').hasClass('empty')) {
|
||||
var button = container.find('#prevImage').get(0);
|
||||
flashButton(button);
|
||||
switchToImageRelative(-1);
|
||||
}
|
||||
},
|
||||
previousDisplaySet() {
|
||||
OHIF.viewer.moveDisplaySets(false);
|
||||
},
|
||||
nextDisplaySet() {
|
||||
OHIF.viewer.moveDisplaySets(true);
|
||||
},
|
||||
nextPanel: function() {
|
||||
nextActivePanel();
|
||||
},
|
||||
previousPanel: function() {
|
||||
previousActivePanel();
|
||||
},
|
||||
invert: function() {
|
||||
var button = document.getElementById('invert');
|
||||
flashButton(button);
|
||||
invert();
|
||||
},
|
||||
flipV: function() {
|
||||
var button = document.getElementById('flipV');
|
||||
flashButton(button);
|
||||
flipV();
|
||||
},
|
||||
flipH: function() {
|
||||
var button = document.getElementById('flipH');
|
||||
flashButton(button);
|
||||
flipH();
|
||||
},
|
||||
rotateR: function() {
|
||||
var button = document.getElementById('rotateR');
|
||||
flashButton(button);
|
||||
rotateR();
|
||||
},
|
||||
rotateL: function() {
|
||||
var button = document.getElementById('rotateL');
|
||||
flashButton(button);
|
||||
rotateL();
|
||||
},
|
||||
cinePlay: function() {
|
||||
toggleCinePlay();
|
||||
},
|
||||
defaultTool: function() {
|
||||
var tool = toolManager.getDefaultTool();
|
||||
toolManager.setActiveTool(tool);
|
||||
},
|
||||
toggleOverlayTags: function() {
|
||||
var dicomTags = $('.imageViewerViewportOverlay .dicomTag');
|
||||
if (dicomTags.eq(0).css('display') === 'none') {
|
||||
dicomTags.show();
|
||||
} else {
|
||||
dicomTags.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
OHIF.viewer.loadedSeriesData = {};
|
||||
});
|
||||
|
||||
// Define a jQuery reverse function
|
||||
$.fn.reverse = [].reverse;
|
||||
|
||||
function previousActivePanel() {
|
||||
OHIF.log.info('nextActivePanel');
|
||||
var currentIndex = Session.get('activeViewport');
|
||||
currentIndex--;
|
||||
|
||||
var viewports = $('.imageViewerViewport');
|
||||
var numViewports = viewports.length;
|
||||
if (currentIndex < 0) {
|
||||
currentIndex = numViewports - 1;
|
||||
}
|
||||
|
||||
var element = viewports.get(currentIndex);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
setActiveViewport(element);
|
||||
}
|
||||
|
||||
function nextActivePanel() {
|
||||
OHIF.log.info('nextActivePanel');
|
||||
var currentIndex = Session.get('activeViewport');
|
||||
currentIndex++;
|
||||
|
||||
var viewports = $('.imageViewerViewport');
|
||||
var numViewports = viewports.length;
|
||||
if (currentIndex >= numViewports) {
|
||||
currentIndex = 0;
|
||||
}
|
||||
|
||||
var element = viewports.get(currentIndex);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
setActiveViewport(element);
|
||||
}
|
||||
|
||||
function flashButton(button) {
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
|
||||
button.classList.add('active');
|
||||
setTimeout(function() {
|
||||
button.classList.remove('active');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function bindHotkey(hotkey, task) {
|
||||
var hotkeyFunctions = OHIF.viewer.hotkeyFunctions;
|
||||
|
||||
// Only bind defined, non-empty HotKeys
|
||||
if (!hotkey || hotkey === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
var fn;
|
||||
if (task.indexOf('WLPreset') > -1) {
|
||||
var presetName = task.replace('WLPreset', '');
|
||||
fn = function() {
|
||||
applyWLPresetToActiveElement(presetName);
|
||||
};
|
||||
} else {
|
||||
fn = hotkeyFunctions[task];
|
||||
|
||||
// If the function doesn't exist in the
|
||||
// hotkey function list, try the viewer-specific function list
|
||||
if (!fn && OHIF.viewer && OHIF.viewer.functionList) {
|
||||
fn = OHIF.viewer.functionList[task];
|
||||
}
|
||||
}
|
||||
|
||||
if (!fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hotKeyForBinding = hotkey.toLowerCase();
|
||||
|
||||
$(document).bind('keydown', hotKeyForBinding, fn);
|
||||
}
|
||||
|
||||
enableHotkeys = function() {
|
||||
var viewerHotkeys = OHIF.viewer.hotkeys;
|
||||
|
||||
$(document).unbind('keydown');
|
||||
|
||||
Object.keys(viewerHotkeys).forEach(function(task) {
|
||||
var taskHotkeys = viewerHotkeys[task];
|
||||
if (!taskHotkeys || !taskHotkeys.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (taskHotkeys.constructor === Array) {
|
||||
taskHotkeys.forEach(function(hotkey) {
|
||||
bindHotkey(hotkey, task);
|
||||
});
|
||||
} else {
|
||||
// taskHotkeys represents a single key
|
||||
bindHotkey(taskHotkeys, task);
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -1,250 +0,0 @@
|
||||
import { ImageSet } from './classes/ImageSet';
|
||||
|
||||
const sortBySeriesNumberAndAcquisition = (a, b) => {
|
||||
if (a.seriesNumber && b.seriesNumber) {
|
||||
if (a.seriesNumber !== b.seriesNumber) {
|
||||
return a.seriesNumber - b.seriesNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if (a.acquisitionDateTime && b.acquisitionDateTime) {
|
||||
return a.acquisitionDateTime.localeCompare(b.acquisitionDateTime);
|
||||
}
|
||||
};
|
||||
|
||||
const makeImageSet = sopInstances => {
|
||||
const imageSet = new ImageSet(sopInstances);
|
||||
const sopInstance = sopInstances[0];
|
||||
|
||||
// list of attributes to be appended to ImageSet instance...
|
||||
const attributes = {
|
||||
seriesInstanceUid: sopInstance.getRawValue('x0020000e'),
|
||||
seriesNumber: sopInstance.getIntValue('x00200011'),
|
||||
seriesDescription: sopInstance.getRawValue('x0008103e', ''),
|
||||
acquisitionDateTime: sopInstance.getRawValue('x00080022', '') + sopInstance.getRawValue('x00080032', ''),
|
||||
numImageFrames: sopInstances.length,
|
||||
frameRate: sopInstance.getFloatValue('x00181063', 0, 0),
|
||||
studyInstanceUid: sopInstance.getRawValue('x0020000d'),
|
||||
displaySetInstanceUid: imageSet.uid // create an alias for the imageSet UID
|
||||
};
|
||||
|
||||
const frameTime = sopInstance.getFloatValue('x00181063', 0, 0);
|
||||
const recommendedDisplayFrameRate = sopInstance.getFloatValue('x00082144', 0, 0);
|
||||
if (frameTime) {
|
||||
// FrameTime is in milliseconds, so we use 1000/frameTime to calculate
|
||||
// the number of frames per second.
|
||||
attributes.frameRate = 1000 / frameTime;
|
||||
attributes.isClip = true;
|
||||
} else if (recommendedDisplayFrameRate) {
|
||||
// Recommended Display FrameRate is specified in frames per second as an integer
|
||||
attributes.frameRate = recommendedDisplayFrameRate;
|
||||
attributes.isClip = true;
|
||||
}
|
||||
|
||||
imageSet.setAttributes(attributes);
|
||||
|
||||
// Sort the images in this series
|
||||
imageSet.sortBy( (a, b) => {
|
||||
const aInstanceNumber = a.getFloatValue('x00200013');
|
||||
const bInstanceNumber = b.getFloatValue('x00200013');
|
||||
|
||||
if (aInstanceNumber && bInstanceNumber) {
|
||||
if (aInstanceNumber !== bInstanceNumber) {
|
||||
return aInstanceNumber - bInstanceNumber;
|
||||
}
|
||||
}
|
||||
|
||||
const aAcquisitionNumber = a.getFloatValue('x00200012');
|
||||
const bAcquisitionNumber = b.getFloatValue('x00200012');
|
||||
|
||||
if (aAcquisitionNumber && bAcquisitionNumber) {
|
||||
if (aAcquisitionNumber !== bAcquisitionNumber) {
|
||||
return aAcquisitionNumber - bAcquisitionNumber;
|
||||
}
|
||||
}
|
||||
|
||||
const aAcquisitionDateTime = a.getRawValue('x00080022', '') + a.getRawValue('x00080032', '');
|
||||
const bAcquisitionDateTime = b.getRawValue('x00080022', '') + b.getRawValue('x00080032', '');
|
||||
|
||||
if (aAcquisitionDateTime && bAcquisitionDateTime) {
|
||||
return aAcquisitionDateTime.localeCompare(bAcquisitionDateTime);
|
||||
}
|
||||
});
|
||||
|
||||
return imageSet;
|
||||
};
|
||||
|
||||
const isMultiFrame = instanceView => {
|
||||
const numFrames = instanceView.getIntValue('x00280008');
|
||||
return (numFrames > 1);
|
||||
};
|
||||
|
||||
const isSingleImageModality = modality => {
|
||||
const singleImageModalities = ['CR', 'MG', 'DX', 'RG', 'PX', 'XA', 'XR']
|
||||
return singleImageModalities.indexOf(modality) > -1;
|
||||
};
|
||||
|
||||
const seriesSplittingRules = [
|
||||
{
|
||||
tag: 'x00180010', // ContrastBolusAgent
|
||||
},
|
||||
{
|
||||
tag: 'x00180086', // Echo Number
|
||||
},
|
||||
|
||||
// --- Some other potential examples of tags to split on --- //
|
||||
/*{
|
||||
tag: 'x00180020', // Scanning Sequence
|
||||
},
|
||||
{
|
||||
tag: 'x00180050', // Slice Thickness
|
||||
},*/
|
||||
/*{
|
||||
tag: 'x00180081', // Echo Time
|
||||
},
|
||||
{
|
||||
tag: 'x00181210', // Convolution Kernel
|
||||
},*/
|
||||
/*{
|
||||
tag: 'x00200012', // Acquisition Number
|
||||
}*/
|
||||
];
|
||||
|
||||
const stackOfInstancesToDisplaySets = (sopInstances, seriesView) => {
|
||||
// If no instances are provided, return an empty array
|
||||
if (!sopInstances.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Create an empty array to store our display sets in
|
||||
const displaySets = [];
|
||||
|
||||
// Use Underscore's groupBy function to group our sopInstances
|
||||
// by a key. In our case, the key is a combined string which represents
|
||||
// the value of the DICOM tags listed in the seriesSplittingRules array.
|
||||
// Currently this uses tags for EchoNumber and ContrastBolusAgent.
|
||||
const groups = _.groupBy(sopInstances, sopInstance => {
|
||||
// Create an empty string to store our key
|
||||
let result = '';
|
||||
|
||||
// For each rule, find out if the tag exists
|
||||
seriesSplittingRules.forEach(rule => {
|
||||
// Include a delimitation character between each tag value
|
||||
result += ';'
|
||||
|
||||
// If the tag exists, concatenate its value to our key
|
||||
if (sopInstance.tagExists(rule.tag)) {
|
||||
result += sopInstance.getRawValue(rule.tag);
|
||||
}
|
||||
});
|
||||
|
||||
// Return the key to be used for grouping.
|
||||
return result;
|
||||
})
|
||||
|
||||
const seriesInstanceCount = seriesView.getInstanceCount();
|
||||
|
||||
Object.keys(groups).forEach(groupKey => {
|
||||
// For each group, obtain the instances in the stack
|
||||
const stackInstances = groups[groupKey];
|
||||
|
||||
// Create a new display set from the images in this stack
|
||||
const displaySet = makeImageSet(stackInstances);
|
||||
displaySet.setAttribute('seriesInstanceCount', seriesInstanceCount);
|
||||
|
||||
displaySets.push(displaySet);
|
||||
});
|
||||
|
||||
return displaySets;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function extracts and produces sorted lists of image sets and non-viewable instance
|
||||
* sets from a studyMetadata {StudyMetadata instance}.
|
||||
*
|
||||
* If an optional series number is specified, only the image set with this series number
|
||||
* will be returned (as the sole element in an array).
|
||||
*
|
||||
* The function returns an object with two fields, imageSets and nonViewable, both of which
|
||||
* are arrays. imageSets is an array of sorted image sets and nonViewable is an array of
|
||||
* non-viewable sopInstances.
|
||||
*
|
||||
* @param studyMetadata
|
||||
* @param {number} [seriesNumber] One series number. If specified, the function only returns the imageSet with this seriesNumber
|
||||
*
|
||||
* @returns {{imageSets: Array, nonViewable: Array}}
|
||||
*/
|
||||
getSortedData = function(studyMetadata, seriesNumber) {
|
||||
let imageSets = [];
|
||||
let nonViewable = [];
|
||||
|
||||
studyMetadata.forEachSeries((series, seriesNum) => {
|
||||
const firstInstance = series.getInstanceByIndex(0);
|
||||
|
||||
// If a specific series number is given, skip all series except this one
|
||||
if (seriesNumber !== undefined && firstInstance.getIntValue('x00200011', '') !== seriesNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sopInstances = [];
|
||||
let imageSet;
|
||||
|
||||
const seriesInstanceCount = series.getInstanceCount();
|
||||
|
||||
series.forEachInstance(instanceMetadata => {
|
||||
// Skip non image types (an image must have the 'rows' tag)
|
||||
const rows = instanceMetadata.tagExists('x00280010');
|
||||
|
||||
if (!rows) {
|
||||
nonViewable.push(instanceMetadata);
|
||||
return;
|
||||
}
|
||||
|
||||
const modality = firstInstance.getRawValue('x00080060', '');
|
||||
const singleImageModality = isSingleImageModality(modality);
|
||||
|
||||
// If we detect a multi-frame instance
|
||||
if (isMultiFrame(instanceMetadata)) {
|
||||
// First, sort all sopInstances currently in our stack into display sets using
|
||||
// our series splitting rules
|
||||
const displaySets = stackOfInstancesToDisplaySets(sopInstances, series);
|
||||
imageSets = imageSets.concat(displaySets);
|
||||
|
||||
// Next, make another display set for the multi-frame instance
|
||||
imageSet = makeImageSet([ instanceMetadata ]);
|
||||
imageSet.setAttributes({
|
||||
seriesInstanceCount: seriesInstanceCount,
|
||||
numImageFrames: instanceMetadata.getIntValue('x00280008', 0)
|
||||
});
|
||||
|
||||
imageSets.push(imageSet);
|
||||
|
||||
// Reset our stack of sopInstances
|
||||
sopInstances = [];
|
||||
} else if (singleImageModality) {
|
||||
imageSet = makeImageSet([ instanceMetadata ]);
|
||||
imageSet.setAttribute('seriesInstanceCount', seriesInstanceCount);
|
||||
imageSets.push(imageSet);
|
||||
} else {
|
||||
// If no multi-frame instances have been discovered
|
||||
sopInstances.push(instanceMetadata);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Create display sets from any remaining sopInstances in the series
|
||||
const displaySets = stackOfInstancesToDisplaySets(sopInstances, series);
|
||||
imageSets = imageSets.concat(displaySets);
|
||||
});
|
||||
|
||||
// sort imageSets
|
||||
imageSets.sort(sortBySeriesNumberAndAcquisition);
|
||||
nonViewable.sort(sortBySeriesNumberAndAcquisition);
|
||||
|
||||
return {
|
||||
imageSets,
|
||||
nonViewable
|
||||
};
|
||||
};
|
||||
|
||||
export { getSortedData };
|
||||
@ -1,234 +0,0 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
// Displays Series in Viewports given a Protocol and list of Studies
|
||||
LayoutManager = class LayoutManager {
|
||||
constructor(parentNode, studies) {
|
||||
OHIF.log.info('LayoutManager');
|
||||
|
||||
this.parentNode = parentNode;
|
||||
this.studies = studies;
|
||||
this.viewportData = [];
|
||||
this.layoutTemplateName = 'gridLayout';
|
||||
this.layoutProps = {
|
||||
rows: 1,
|
||||
columns: 1
|
||||
};
|
||||
|
||||
this.viewportData = [];
|
||||
|
||||
this.isZoomed = false;
|
||||
|
||||
const updateSessionFn = () => Tracker.afterFlush(() => Session.set('LayoutManagerUpdated', Random.id()));
|
||||
this.updateSession = _.throttle(updateSessionFn, 300);
|
||||
}
|
||||
|
||||
getNumberOfViewports() {
|
||||
return this.layoutProps.rows * this.layoutProps.columns;
|
||||
}
|
||||
|
||||
setDefaultViewportData() {
|
||||
const self = this;
|
||||
|
||||
// Get the number of vieports to be rendered
|
||||
const viewportsAmount = this.getNumberOfViewports();
|
||||
|
||||
// Store the old viewport data and reset the current
|
||||
const oldViewportData = self.viewportData;
|
||||
|
||||
// Get the studies and display sets sequence map
|
||||
const sequenceMap = OHIF.viewer.getDisplaySetSequenceMap();
|
||||
|
||||
// Check if the display sets are sequenced
|
||||
const isSequenced = OHIF.viewer.isDisplaySetsSequenced(sequenceMap);
|
||||
|
||||
// Define the current viewport index and the viewport data array
|
||||
let currentViewportIndex = 0;
|
||||
if (viewportsAmount > oldViewportData.length && oldViewportData.length && isSequenced) {
|
||||
// Keep the displayed display sets
|
||||
self.viewportData = oldViewportData;
|
||||
currentViewportIndex = oldViewportData.length;
|
||||
} else if (viewportsAmount <= oldViewportData.length) {
|
||||
// Reduce the original displayed display sets
|
||||
self.viewportData = oldViewportData.slice(0, viewportsAmount);
|
||||
return;
|
||||
} else {
|
||||
// Reset all display sets
|
||||
self.viewportData = [];
|
||||
}
|
||||
|
||||
// Get all the display sets for the viewer studies
|
||||
let displaySets = [];
|
||||
this.studies.forEach(study => {
|
||||
study.displaySets.forEach(displaySet => {
|
||||
displaySet.images.length && displaySets.push(displaySet);
|
||||
});
|
||||
});
|
||||
|
||||
// Get the display sets that will be appended to the current ones
|
||||
let appendix;
|
||||
const currentLength = self.viewportData.length;
|
||||
if (currentLength) {
|
||||
// TODO: isolate displaySets array by study (maybe a map?)
|
||||
const beginIndex = sequenceMap.values().next().value[0].displaySetIndex + currentLength;
|
||||
const endIndex = beginIndex + (viewportsAmount - currentLength);
|
||||
appendix = displaySets.slice(beginIndex, endIndex);
|
||||
} else {
|
||||
// Get available display sets from the first to the grid size
|
||||
appendix = displaySets.slice(0, viewportsAmount);
|
||||
}
|
||||
|
||||
// Generate the additional data based on the appendix
|
||||
const additionalData = [];
|
||||
appendix.forEach((displaySet, index) => {
|
||||
additionalData.push({
|
||||
viewportIndex: currentViewportIndex + index,
|
||||
studyInstanceUid: displaySet.studyInstanceUid,
|
||||
seriesInstanceUid: displaySet.seriesInstanceUid,
|
||||
displaySetInstanceUid: displaySet.displaySetInstanceUid,
|
||||
sopInstanceUid: displaySet.images[0].sopInstanceUid
|
||||
});
|
||||
});
|
||||
|
||||
// Append the additional data with the viewport data
|
||||
self.viewportData = self.viewportData.concat(additionalData);
|
||||
|
||||
// Push empty objects if the amount is lesser than the grid size
|
||||
while (self.viewportData.length < viewportsAmount) {
|
||||
self.viewportData.push({});
|
||||
}
|
||||
}
|
||||
|
||||
updateViewports() {
|
||||
OHIF.log.info('updateViewports');
|
||||
|
||||
if (!this.viewportData ||
|
||||
!this.viewportData.length ||
|
||||
this.viewportData.length !== this.getNumberOfViewports()) {
|
||||
this.setDefaultViewportData();
|
||||
}
|
||||
|
||||
// imageViewerViewports occasionally needs relevant layout data in order to set
|
||||
// the element style of the viewport in question
|
||||
var layoutProps = this.layoutProps;
|
||||
var data = $.extend({
|
||||
viewportData: []
|
||||
}, layoutProps);
|
||||
|
||||
this.viewportData.forEach(function(viewportData) {
|
||||
var viewportDataAndLayoutProps = $.extend(viewportData, layoutProps);
|
||||
data.viewportData.push(viewportDataAndLayoutProps);
|
||||
});
|
||||
|
||||
var layoutTemplate = Template[this.layoutTemplateName];
|
||||
|
||||
$(this.parentNode).html('');
|
||||
Blaze.renderWithData(layoutTemplate, data, this.parentNode);
|
||||
|
||||
this.updateSession();
|
||||
|
||||
this.isZoomed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function destroys and re-renders the imageViewerViewport template.
|
||||
* It uses the data provided to load a new display set into the produced viewport.
|
||||
*
|
||||
* @param viewportIndex
|
||||
* @param data
|
||||
*/
|
||||
rerenderViewportWithNewDisplaySet(viewportIndex, data) {
|
||||
// The parent container is identified because it is later removed from the DOM
|
||||
var element = $('.imageViewerViewport').eq(viewportIndex);
|
||||
var container = element.parents('.viewportContainer').get(0);
|
||||
|
||||
// Record the current viewportIndex so this can be passed into the re-rendering call
|
||||
data.viewportIndex = viewportIndex;
|
||||
|
||||
// Update the dictionary of loaded displaySet for the specified viewport
|
||||
this.viewportData[viewportIndex] = {
|
||||
viewportIndex: viewportIndex,
|
||||
displaySetInstanceUid: data.displaySetInstanceUid,
|
||||
seriesInstanceUid: data.seriesInstanceUid,
|
||||
studyInstanceUid: data.studyInstanceUid,
|
||||
renderedCallback: data.renderedCallback,
|
||||
currentImageIdIndex: data.currentImageIdIndex || 0
|
||||
};
|
||||
|
||||
// Remove the hover styling
|
||||
element.find('canvas').not('.magnifyTool').removeClass('faded');
|
||||
|
||||
// Remove the whole template, add in the new one
|
||||
var viewportContainer = element.parents('.removable');
|
||||
|
||||
var newViewportContainer = document.createElement('div');
|
||||
newViewportContainer.className = 'removable';
|
||||
|
||||
// Remove the parent element of the template
|
||||
// This is a workaround since otherwise Blaze UI onDestroyed doesn't fire
|
||||
viewportContainer.remove();
|
||||
|
||||
container.appendChild(newViewportContainer);
|
||||
|
||||
// Render and insert the template
|
||||
Blaze.renderWithData(Template.imageViewerViewport, data, newViewportContainer);
|
||||
|
||||
this.updateSession();
|
||||
}
|
||||
|
||||
enlargeViewport(viewportIndex) {
|
||||
OHIF.log.info('Zooming Into Viewport: ' + viewportIndex);
|
||||
|
||||
if (!this.viewportData ||
|
||||
!this.viewportData.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clone the array for later
|
||||
this.previousViewportData = this.viewportData.slice(0);
|
||||
|
||||
var singleViewportData = $.extend({}, this.viewportData[viewportIndex]);
|
||||
singleViewportData.rows = 1;
|
||||
singleViewportData.columns = 1;
|
||||
singleViewportData.viewportIndex = 0;
|
||||
|
||||
var data = {
|
||||
viewportData: [singleViewportData],
|
||||
rows: 1,
|
||||
columns: 1
|
||||
};
|
||||
|
||||
var layoutTemplate = Template['gridLayout'];
|
||||
|
||||
$(this.parentNode).html('');
|
||||
Blaze.renderWithData(layoutTemplate, data, this.parentNode);
|
||||
|
||||
this.isZoomed = true;
|
||||
this.zoomedViewportIndex = viewportIndex;
|
||||
this.viewportData = data.viewportData;
|
||||
|
||||
this.updateSession();
|
||||
}
|
||||
|
||||
resetPreviousLayout() {
|
||||
if (!this.isZoomed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.previousViewportData[this.zoomedViewportIndex] = $.extend({}, this.viewportData[0]);
|
||||
this.previousViewportData[this.zoomedViewportIndex].viewportIndex = this.zoomedViewportIndex;
|
||||
this.viewportData = this.previousViewportData;
|
||||
this.updateViewports();
|
||||
}
|
||||
|
||||
toggleEnlargement(viewportIndex) {
|
||||
if (this.isZoomed) {
|
||||
this.resetPreviousLayout();
|
||||
} else {
|
||||
// Don't enlarge the viewport if we only have one Viewport
|
||||
// to begin with
|
||||
if (this.getNumberOfViewports() > 1) {
|
||||
this.enlargeViewport(viewportIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1,6 +0,0 @@
|
||||
toggleDialog = element => {
|
||||
const $element = $(element);
|
||||
const isClosed = $element.hasClass('dialog-open');
|
||||
$element.toggleClass('dialog-closed', isClosed);
|
||||
$element.toggleClass('dialog-open', !isClosed);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user