Removing ohif-cornerstone as a dependency for ohif-viewerbase (Final step)
This commit is contained in:
parent
b866e6e6c7
commit
c2c8a43c3a
@ -6,6 +6,7 @@ import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import 'meteor/ohif:cornerstone';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
import 'meteor/ohif:metadata';
|
||||
|
||||
@ -15,6 +16,15 @@ Meteor.startup(() => {
|
||||
Session.set('MeasurementsReady', false);
|
||||
|
||||
OHIF.viewer.stackImagePositionOffsetSynchronizer = new OHIF.viewerbase.StackImagePositionOffsetSynchronizer();
|
||||
|
||||
// Create the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer('CornerstoneNewImage', cornerstoneTools.updateImageSynchronizer);
|
||||
|
||||
OHIF.viewer.metadataProvider = OHIF.cornerstone.metadataProvider;
|
||||
|
||||
// Metadata configuration
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
cornerstoneTools.metaData.addProvider(metadataProvider.provider.bind(metadataProvider));
|
||||
});
|
||||
|
||||
Template.viewer.onCreated(() => {
|
||||
|
||||
@ -4,6 +4,7 @@ import { Template } from 'meteor/templating';
|
||||
import { ReactiveDict } from 'meteor/reactive-dict';
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import 'meteor/ohif:cornerstone';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
import 'meteor/ohif:metadata';
|
||||
|
||||
@ -31,6 +32,15 @@ Meteor.startup(() => {
|
||||
};
|
||||
|
||||
OHIF.viewer.stackImagePositionOffsetSynchronizer = new OHIF.viewerbase.StackImagePositionOffsetSynchronizer();
|
||||
|
||||
// Create the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer('CornerstoneNewImage', cornerstoneTools.updateImageSynchronizer);
|
||||
|
||||
OHIF.viewer.metadataProvider = OHIF.cornerstone.metadataProvider;
|
||||
|
||||
// Metadata configuration
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
cornerstoneTools.metaData.addProvider(metadataProvider.provider.bind(metadataProvider));
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -8,7 +8,8 @@ const OHIF = {
|
||||
log: {},
|
||||
ui: {},
|
||||
utils: {},
|
||||
viewer: {}
|
||||
viewer: {},
|
||||
cornerstone: {}
|
||||
};
|
||||
|
||||
// Expose the OHIF object to the client if it is on development mode
|
||||
|
||||
4
Packages/ohif-cornerstone/client/index.js
Normal file
4
Packages/ohif-cornerstone/client/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
import { Cornerstone } from '../namespace';
|
||||
|
||||
import { MetadataProvider } from './lib/classes/MetadataProvider';
|
||||
Cornerstone.metadataProvider = new MetadataProvider();
|
||||
257
Packages/ohif-cornerstone/client/lib/classes/MetadataProvider.js
Normal file
257
Packages/ohif-cornerstone/client/lib/classes/MetadataProvider.js
Normal file
@ -0,0 +1,257 @@
|
||||
import { parsingUtils } from '../parsingUtils';
|
||||
|
||||
export class MetadataProvider {
|
||||
|
||||
constructor() {
|
||||
this.metadataLookup = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cornerstone Metadata provider to store image meta data
|
||||
* Data from instances, series, and studies are associated with
|
||||
* imageIds to facilitate usage of this information by Cornerstone's Tools
|
||||
*
|
||||
* e.g. the imagePlane metadata object contains instance information about
|
||||
* row/column pixel spacing, patient position, and patient orientation. It
|
||||
* is used in CornerstoneTools to position reference lines and orientation markers.
|
||||
*
|
||||
* @param {String} imageId The Cornerstone ImageId
|
||||
* @param {Object} data An object containing instance, series, and study metadata
|
||||
*/
|
||||
addMetadata(imageId, data) {
|
||||
const instanceMetadata = data.instance;
|
||||
const seriesMetadata = data.series;
|
||||
const studyMetadata = data.study;
|
||||
const imageIndex = data.imageIndex;
|
||||
const numImages = data.numImages;
|
||||
|
||||
const metadata = {};
|
||||
|
||||
metadata.study = {
|
||||
patientId: studyMetadata.patientId,
|
||||
studyInstanceUid: studyMetadata.studyInstanceUid,
|
||||
studyDate: studyMetadata.studyDate,
|
||||
studyTime: studyMetadata.studyTime,
|
||||
studyDescription: studyMetadata.studyDescription,
|
||||
institutionName: studyMetadata.institutionName,
|
||||
patientHistory: studyMetadata.patientHistory
|
||||
};
|
||||
|
||||
metadata.series = {
|
||||
seriesDescription: seriesMetadata.seriesDescription,
|
||||
seriesNumber: seriesMetadata.seriesNumber,
|
||||
modality: seriesMetadata.modality,
|
||||
seriesInstanceUid: seriesMetadata.seriesInstanceUid,
|
||||
numImages: numImages
|
||||
};
|
||||
|
||||
metadata.instance = instanceMetadata;
|
||||
|
||||
metadata.patient = {
|
||||
name: studyMetadata.patientName,
|
||||
id: studyMetadata.patientId,
|
||||
birthDate: studyMetadata.patientBirthDate,
|
||||
sex: studyMetadata.patientSex
|
||||
};
|
||||
|
||||
// If there is sufficient information, populate
|
||||
// the imagePlane object for easier use in the Viewer
|
||||
metadata.imagePlane = this.getImagePlane(instanceMetadata);
|
||||
|
||||
// Add the metadata to the imageId lookup object
|
||||
this.metadataLookup[imageId] = metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a set of metadata to the Cornerstone metadata provider given a specific
|
||||
* imageId, type, and dataset
|
||||
*
|
||||
* @param imageId
|
||||
* @param type (e.g. series, instance, tagDisplay)
|
||||
* @param data
|
||||
*/
|
||||
addSpecificMetadata(imageId, type, data) {
|
||||
const metadata = {};
|
||||
metadata[type] = data;
|
||||
|
||||
this.metadataLookup[imageId] = $.extend(this.metadataLookup[imageId], metadata);
|
||||
}
|
||||
|
||||
|
||||
getFromDataSet(dataSet, type, tag) {
|
||||
if (!dataSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fn = dataSet[type];
|
||||
if (!fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
return fn.call(dataSet, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the related metadata for missing fields given a specified image
|
||||
*
|
||||
* @param image
|
||||
*/
|
||||
updateMetadata(image) {
|
||||
const imageMetadata = this.metadataLookup[image.imageId];
|
||||
if (!imageMetadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
imageMetadata.instance.rows = imageMetadata.instance.rows || image.rows;
|
||||
imageMetadata.instance.columns = imageMetadata.instance.columns || image.columns;
|
||||
|
||||
imageMetadata.instance.sopClassUid = imageMetadata.instance.sopClassUid || this.getFromDataSet(image.data, 'string', 'x00080016');
|
||||
imageMetadata.instance.sopInstanceUid = imageMetadata.instance.sopInstanceUid || this.getFromDataSet(image.data, 'string', 'x00080018');
|
||||
|
||||
imageMetadata.instance.pixelSpacing = imageMetadata.instance.pixelSpacing || this.getFromDataSet(image.data, 'string', 'x00280030');
|
||||
imageMetadata.instance.frameOfReferenceUID = imageMetadata.instance.frameOfReferenceUID || this.getFromDataSet(image.data, 'string', 'x00200052');
|
||||
imageMetadata.instance.imageOrientationPatient = imageMetadata.instance.imageOrientationPatient || this.getFromDataSet(image.data, 'string', 'x00200037');
|
||||
imageMetadata.instance.imagePositionPatient = imageMetadata.instance.imagePositionPatient || this.getFromDataSet(image.data, 'string', 'x00200032');
|
||||
|
||||
imageMetadata.instance.sliceThickness = imageMetadata.instance.sliceThickness || this.getFromDataSet(image.data, 'string', 'x00180050');
|
||||
imageMetadata.instance.sliceLocation = imageMetadata.instance.sliceLocation || this.getFromDataSet(image.data, 'string', 'x00201041');
|
||||
imageMetadata.instance.tablePosition = imageMetadata.instance.tablePosition || this.getFromDataSet(image.data, 'string', 'x00189327');
|
||||
imageMetadata.instance.spacingBetweenSlices = imageMetadata.instance.spacingBetweenSlices || this.getFromDataSet(image.data, 'string', 'x00180088');
|
||||
|
||||
imageMetadata.instance.lossyImageCompression = imageMetadata.instance.lossyImageCompression || this.getFromDataSet(image.data, 'string', 'x00282110');
|
||||
imageMetadata.instance.lossyImageCompressionRatio = imageMetadata.instance.lossyImageCompressionRatio || this.getFromDataSet(image.data, 'string', 'x00282112');
|
||||
|
||||
imageMetadata.instance.frameIncrementPointer = imageMetadata.instance.frameIncrementPointer || this.getFromDataSet(image.data, 'string', 'x00280009');
|
||||
imageMetadata.instance.frameTime = imageMetadata.instance.frameTime || this.getFromDataSet(image.data, 'string', 'x00181063');
|
||||
imageMetadata.instance.frameTimeVector = imageMetadata.instance.frameTimeVector || this.getFromDataSet(image.data, 'string', 'x00181065');
|
||||
|
||||
if (image.data && !imageMetadata.instance.multiframeMetadata) {
|
||||
imageMetadata.instance.multiframeMetadata = this.getMultiframeModuleMetadata(image.data);
|
||||
}
|
||||
|
||||
imageMetadata.imagePlane = imageMetadata.imagePlane || this.getImagePlane(imageMetadata.instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns the imagePlane given the metadata instance
|
||||
*
|
||||
* @param metadataInstance The metadata instance (InstanceMetadata class) containing information to construct imagePlane
|
||||
* @returns imagePlane The constructed imagePlane to be used in viewer easily
|
||||
*/
|
||||
getImagePlane(instance) {
|
||||
if (!instance.rows || !instance.columns || !instance.pixelSpacing ||
|
||||
!instance.frameOfReferenceUID || !instance.imageOrientationPatient ||
|
||||
!instance.imagePositionPatient) {
|
||||
return;
|
||||
}
|
||||
|
||||
const imageOrientation = instance.imageOrientationPatient.split('\\');
|
||||
const imagePosition = instance.imagePositionPatient.split('\\');
|
||||
|
||||
let columnPixelSpacing = 1.0;
|
||||
let rowPixelSpacing = 1.0;
|
||||
if (instance.pixelSpacing) {
|
||||
const split = instance.pixelSpacing.split('\\');
|
||||
rowPixelSpacing = parseFloat(split[0]);
|
||||
columnPixelSpacing = parseFloat(split[1]);
|
||||
}
|
||||
|
||||
return {
|
||||
frameOfReferenceUID:
|
||||
instance.frameOfReferenceUID,
|
||||
rows:
|
||||
instance.rows,
|
||||
columns:
|
||||
instance.columns,
|
||||
rowCosines:
|
||||
new cornerstoneMath.Vector3(parseFloat(imageOrientation[0]), parseFloat(imageOrientation[1]), parseFloat(imageOrientation[2])),
|
||||
columnCosines:
|
||||
new cornerstoneMath.Vector3(parseFloat(imageOrientation[3]), parseFloat(imageOrientation[4]), parseFloat(imageOrientation[5])),
|
||||
imagePositionPatient:
|
||||
new cornerstoneMath.Vector3(parseFloat(imagePosition[0]), parseFloat(imagePosition[1]), parseFloat(imagePosition[2])),
|
||||
rowPixelSpacing:
|
||||
rowPixelSpacing,
|
||||
columnPixelSpacing:
|
||||
columnPixelSpacing,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function extracts miltiframe information from a dicomParser.DataSet object.
|
||||
*
|
||||
* @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).
|
||||
*/
|
||||
getMultiframeModuleMetadata(dataSet) {
|
||||
const imageInfo = {
|
||||
isMultiframeImage: false,
|
||||
frameIncrementPointer: null,
|
||||
numberOfFrames: 0,
|
||||
frameTime: 0,
|
||||
frameTimeVector: null,
|
||||
averageFrameRate: 0 // backwards compatibility only... it might be useless in the future
|
||||
};
|
||||
|
||||
let frameTime;
|
||||
|
||||
if (parsingUtils.isValidDataSet(dataSet)) {
|
||||
|
||||
// (0028,0008) = Number of Frames
|
||||
const numberOfFrames = dataSet.intString('x00280008', -1);
|
||||
if (numberOfFrames > 0) {
|
||||
|
||||
// set multi-frame image indicator
|
||||
imageInfo.isMultiframeImage = true;
|
||||
imageInfo.numberOfFrames = numberOfFrames;
|
||||
|
||||
// (0028,0009) = Frame Increment Pointer
|
||||
const frameIncrementPointer = parsingUtils.attributeTag(dataSet, 'x00280009') || '';
|
||||
|
||||
if (frameIncrementPointer === 'x00181065') {
|
||||
// Frame Increment Pointer points to Frame Time Vector (0018,1065) field
|
||||
const frameTimeVector = parsingUtils.floatArray(dataSet, 'x00181065');
|
||||
if (frameTimeVector instanceof Array && frameTimeVector.length > 0) {
|
||||
imageInfo.frameIncrementPointer = 'frameTimeVector';
|
||||
imageInfo.frameTimeVector = frameTimeVector;
|
||||
frameTime = frameTimeVector.reduce((a, b) => a + b) / frameTimeVector.length;
|
||||
imageInfo.averageFrameRate = 1000 / frameTime;
|
||||
}
|
||||
} else if (frameIncrementPointer === 'x00181063' || frameIncrementPointer === '') {
|
||||
// Frame Increment Pointer points to Frame Time (0018,1063) field or is not defined (for addtional flexibility).
|
||||
// Yet another value is possible for this field (5200,9230 for Multi-frame Functional Groups)
|
||||
// but that case is currently not supported.
|
||||
frameTime = dataSet.floatString('x00181063', -1);
|
||||
if (frameTime > 0) {
|
||||
imageInfo.frameIncrementPointer = 'frameTime';
|
||||
imageInfo.frameTime = frameTime;
|
||||
imageInfo.averageFrameRate = 1000 / frameTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return imageInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up metadata for Cornerstone Tools given a specified type and imageId
|
||||
* A type may be, e.g. 'study', or 'patient', or 'imagePlane'. These types
|
||||
* are keys in the stored metadata objects.
|
||||
*
|
||||
* @param type
|
||||
* @param imageId
|
||||
* @returns {Object} Relevant metadata of the specified type
|
||||
*/
|
||||
provider(type, imageId) {
|
||||
const imageMetadata = this.metadataLookup[imageId];
|
||||
if (!imageMetadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (imageMetadata.hasOwnProperty(type)) {
|
||||
return imageMetadata[type];
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import {dicomParser} from 'meteor/ohif:cornerstone';
|
||||
import { dicomParser } from 'meteor/ohif:cornerstone';
|
||||
|
||||
/**
|
||||
* A small set of utilities to help parsing DICOM element values.
|
||||
13
Packages/ohif-cornerstone/main.js
Normal file
13
Packages/ohif-cornerstone/main.js
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Import namespace...
|
||||
*/
|
||||
|
||||
import { OHIF, Cornerstone } from './namespace.js';
|
||||
|
||||
/**
|
||||
* Import scripts that will populate the Cornerstone namespace as a side effect only import. This is effectively the public API...
|
||||
*/
|
||||
|
||||
import './client/'; // which is actually: import './client/index.js';
|
||||
|
||||
export { OHIF, Cornerstone };
|
||||
25
Packages/ohif-cornerstone/namespace.js
Normal file
25
Packages/ohif-cornerstone/namespace.js
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Import main dependency
|
||||
*/
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/**
|
||||
* Append Cornerstone namespace
|
||||
*/
|
||||
|
||||
const Cornerstone = {
|
||||
...OHIF.cornerstone
|
||||
};
|
||||
|
||||
/**
|
||||
* Append Cornerstone namespace to OHIF namespace
|
||||
*/
|
||||
|
||||
OHIF.cornerstone = Cornerstone;
|
||||
|
||||
/**
|
||||
* Export relevant objects
|
||||
*/
|
||||
|
||||
export { OHIF, Cornerstone };
|
||||
@ -7,8 +7,12 @@ Package.describe({
|
||||
Package.onUse(function(api) {
|
||||
api.versionsFrom('1.4');
|
||||
|
||||
api.use('ecmascript');
|
||||
|
||||
api.use('jquery');
|
||||
|
||||
api.use('ohif:core');
|
||||
|
||||
api.addFiles('client/cornerstone.js', 'client', {
|
||||
bare: true
|
||||
});
|
||||
@ -42,4 +46,6 @@ Package.onUse(function(api) {
|
||||
api.export('cornerstoneTools', 'client');
|
||||
api.export('cornerstoneWADOImageLoader', 'client');
|
||||
api.export('dicomParser', 'client');
|
||||
|
||||
api.mainModule('main.js', 'client');
|
||||
});
|
||||
|
||||
@ -14,7 +14,6 @@ import { updateCrosshairsSynchronizer } from '../../../lib/updateCrosshairsSynch
|
||||
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';
|
||||
|
||||
const allCornerstoneEvents = 'CornerstoneToolsMouseDown CornerstoneToolsMouseDownActivate ' +
|
||||
@ -110,7 +109,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
||||
// The ViewportLoading object relates the viewport elements with whichever
|
||||
// image is currently being loaded into them. This is useful so that we can
|
||||
// place progress (download %) for each image inside the proper viewports.
|
||||
ViewportLoading[viewportIndex] = imageId;
|
||||
window.ViewportLoading[viewportIndex] = imageId;
|
||||
|
||||
// Enable Cornerstone for the viewport element
|
||||
const options = {
|
||||
@ -159,6 +158,14 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Additional tasks for metadata provider. If using your own
|
||||
// metadata provider, this may not be necessary.
|
||||
// updateMetadata is important, though, to update image metadata that
|
||||
// for any reason was missing some information such as rows, columns,
|
||||
// sliceThickness, etc (See MetadataProvider class from ohif-cornerstone package)
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
const isUpdateMetadataDefined = metadataProvider && typeof metadataProvider.updateMetadata === 'function';
|
||||
|
||||
// loadAndCacheImage configurable callbacks
|
||||
const callbacks = imageViewerViewportData.callbacks;
|
||||
|
||||
@ -188,8 +195,10 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
||||
enabledElement.image = image;
|
||||
enabledElement.viewport = cornerstone.getDefaultViewport(enabledElement.canvas, image);
|
||||
|
||||
// Update the metaData for missing fields
|
||||
updateMetaData(image);
|
||||
if (isUpdateMetadataDefined) {
|
||||
// Update the metaData for missing fields
|
||||
metadataProvider.updateMetadata(image);
|
||||
}
|
||||
|
||||
// Check if there are default viewport settings for this sopClassUid
|
||||
if (!displaySet.images || !displaySet.images.length) {
|
||||
@ -230,7 +239,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
||||
|
||||
// Remove the data for this viewport from the ViewportLoading object
|
||||
// This will stop the loading percentage complete from being displayed.
|
||||
delete ViewportLoading[viewportIndex];
|
||||
delete window.ViewportLoading[viewportIndex];
|
||||
|
||||
// Call the handler function that represents the end of the image loading phase
|
||||
// (e.g. hide the progress text box)
|
||||
@ -330,8 +339,10 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
||||
// since this callback function is called multiple times (eg: when a tool is
|
||||
// enabled/disabled -> cornerstone[toolName].tool.enable)
|
||||
|
||||
// Update the metaData for missing fields
|
||||
updateMetaData(eventData.enabledElement.image);
|
||||
if(isUpdateMetadataDefined) {
|
||||
// Update the metaData for missing fields
|
||||
metadataProvider.updateMetadata(eventData.enabledElement.image);
|
||||
}
|
||||
|
||||
// Update the templateData with the new imageId
|
||||
// This allows the template helpers to update reactively
|
||||
@ -507,43 +518,9 @@ const setDisplaySet = (data, displaySetInstanceUid, templateData) => {
|
||||
loadDisplaySetIntoViewport(data, templateData);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function searches an object to return the keys that contain a specific value
|
||||
*
|
||||
* @param object {object} The object to be searched
|
||||
* @param value The value to be found
|
||||
*
|
||||
* @returns {array} The keys for which the object has the specified value
|
||||
*/
|
||||
const getKeysByValue = (object, value) => {
|
||||
// http://stackoverflow.com/questions/9907419/javascript-object-get-key-by-value
|
||||
return Object.keys(object).filter(key => object[key] === value);
|
||||
};
|
||||
|
||||
Meteor.startup(function() {
|
||||
// On Meteor startup, define the global objects used to store loading imageIds
|
||||
// by viewport / thumbnail element
|
||||
ViewportLoading = {};
|
||||
|
||||
// Whenever the CornerstoneImageLoadProgress is fired, identify which viewports
|
||||
// the "in-progress" image is to be displayed in. Then pass the percent complete
|
||||
// via the Meteor Session to the other templates to be displayed in the relevant viewports.
|
||||
$(cornerstone).on('CornerstoneImageLoadProgress', function(e, eventData) {
|
||||
viewportIndices = getKeysByValue(ViewportLoading, eventData.imageId);
|
||||
viewportIndices.forEach(function(viewportIndex) {
|
||||
Session.set('CornerstoneLoadProgress' + viewportIndex, eventData.percentComplete);
|
||||
});
|
||||
|
||||
const encodedId = OHIF.string.encodeId(eventData.imageId);
|
||||
Session.set('CornerstoneThumbnailLoadProgress' + encodedId, eventData.percentComplete);
|
||||
});
|
||||
|
||||
const config = {
|
||||
magnifySize: 300,
|
||||
magnificationLevel: 3
|
||||
};
|
||||
|
||||
cornerstoneTools.magnify.setConfiguration(config);
|
||||
Meteor.startup(() => {
|
||||
window.ViewportLoading = window.ViewportLoading || {};
|
||||
toolManager.configureLoadProcess();
|
||||
});
|
||||
|
||||
Template.imageViewerViewport.onRendered(function() {
|
||||
|
||||
@ -3,36 +3,41 @@ import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Meteor.startup(function() {
|
||||
cornerstoneTools.loadHandlerManager.setStartLoadHandler(startLoadingHandler);
|
||||
cornerstoneTools.loadHandlerManager.setEndLoadHandler(doneLoadingHandler);
|
||||
cornerstoneTools.loadHandlerManager.setErrorLoadingHandler(errorLoadingHandler);
|
||||
Meteor.startup(() => {
|
||||
// This checking is necessary because cornerstoneTools may not have some tools available.
|
||||
// Example: when an app defines its own cornerstone's lib versions, so it
|
||||
// uses only ohif-viewerbase and not ohif-cornerstone and those libs are added later.
|
||||
if (cornerstoneTools.loadHandlerManager) {
|
||||
cornerstoneTools.loadHandlerManager.setStartLoadHandler(startLoadingHandler);
|
||||
cornerstoneTools.loadHandlerManager.setEndLoadHandler(doneLoadingHandler);
|
||||
cornerstoneTools.loadHandlerManager.setErrorLoadingHandler(errorLoadingHandler);
|
||||
}
|
||||
});
|
||||
|
||||
var loadHandlerTimeout;
|
||||
let loadHandlerTimeout;
|
||||
|
||||
const startLoadingHandler = function(element) {
|
||||
const startLoadingHandler = element => {
|
||||
clearTimeout(loadHandlerTimeout);
|
||||
loadHandlerTimeout = setTimeout(function() {
|
||||
loadHandlerTimeout = setTimeout(() => {
|
||||
console.log('startLoading');
|
||||
var elem = $(element);
|
||||
const elem = $(element);
|
||||
elem.siblings('.imageViewerErrorLoadingIndicator').css('display', 'none');
|
||||
elem.find('canvas').not('.magnifyTool').addClass('faded');
|
||||
elem.siblings('.imageViewerLoadingIndicator').css('display', 'block');
|
||||
}, OHIF.viewer.loadIndicatorDelay);
|
||||
};
|
||||
|
||||
const doneLoadingHandler = function(element) {
|
||||
const doneLoadingHandler = element => {
|
||||
clearTimeout(loadHandlerTimeout);
|
||||
var elem = $(element);
|
||||
const elem = $(element);
|
||||
elem.siblings('.imageViewerErrorLoadingIndicator').css('display', 'none');
|
||||
elem.find('canvas').not('.magnifyTool').removeClass('faded');
|
||||
elem.siblings('.imageViewerLoadingIndicator').css('display', 'none');
|
||||
};
|
||||
|
||||
const errorLoadingHandler = function(element, imageId, error, source) {
|
||||
const errorLoadingHandler = (element, imageId, error, source) => {
|
||||
clearTimeout(loadHandlerTimeout);
|
||||
var elem = $(element);
|
||||
const elem = $(element);
|
||||
|
||||
// Could probably chain all of these, but this is more readable
|
||||
elem.find('canvas').not('.magnifyTool').removeClass('faded');
|
||||
@ -43,14 +48,14 @@ const errorLoadingHandler = function(element, imageId, error, source) {
|
||||
return;
|
||||
}
|
||||
|
||||
var errorLoadingIndicator = elem.siblings('.imageViewerErrorLoadingIndicator');
|
||||
const errorLoadingIndicator = elem.siblings('.imageViewerErrorLoadingIndicator');
|
||||
errorLoadingIndicator.css('display', 'block');
|
||||
|
||||
// This is just used to expand upon some error messages that are sent
|
||||
// when things fail. An example is a network error throwing the error
|
||||
// which is only described as "network".
|
||||
var errorDetails = {
|
||||
network: "A network error has occurred"
|
||||
const errorDetails = {
|
||||
network: 'A network error has occurred'
|
||||
// We need to expand this further when we see more obscure error messages
|
||||
};
|
||||
|
||||
@ -58,17 +63,17 @@ const errorLoadingHandler = function(element, imageId, error, source) {
|
||||
error = errorDetails[error];
|
||||
}
|
||||
|
||||
errorLoadingIndicator.find('.description').text("An error has occurred while loading image: " + imageId);
|
||||
errorLoadingIndicator.find('.description').text(`An error has occurred while loading image: ${imageId}`);
|
||||
if (error) {
|
||||
errorLoadingIndicator.find('.details').text("Details: " + error);
|
||||
errorLoadingIndicator.find('.details').text(`Details: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
Template.loadingIndicator.helpers({
|
||||
'percentComplete'() {
|
||||
var percentComplete = Session.get('CornerstoneLoadProgress' + this.viewportIndex);
|
||||
const percentComplete = Session.get('CornerstoneLoadProgress' + this.viewportIndex);
|
||||
if (percentComplete && percentComplete !== 100) {
|
||||
return percentComplete + '%';
|
||||
return `${percentComplete}%`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -10,9 +10,6 @@ import { ResizeViewportManager } from '../../../lib/classes/ResizeViewportManage
|
||||
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();
|
||||
});
|
||||
|
||||
|
||||
@ -76,16 +76,6 @@ import { getInstanceClassDefaultViewport, setInstanceClassDefaultViewportFunctio
|
||||
Viewerbase.getInstanceClassDefaultViewport = getInstanceClassDefaultViewport;
|
||||
Viewerbase.setInstanceClassDefaultViewportFunction = setInstanceClassDefaultViewportFunction;
|
||||
|
||||
// setMammogramViewportAlignment
|
||||
import { setMammogramViewportAlignment } from './lib/setMammogramViewportAlignment';
|
||||
Viewerbase.setMammogramViewportAlignment = setMammogramViewportAlignment;
|
||||
|
||||
// addMetaData, addSpecificMetadata, updateMetaData
|
||||
import { addMetaData, addSpecificMetadata, updateMetaData } from './lib/metaDataProvider';
|
||||
Viewerbase.addMetaData = addMetaData;
|
||||
Viewerbase.addSpecificMetadata = addSpecificMetadata;
|
||||
Viewerbase.updateMetaData = updateMetaData;
|
||||
|
||||
// displayReferenceLines
|
||||
import { displayReferenceLines } from './lib/displayReferenceLines';
|
||||
Viewerbase.displayReferenceLines = displayReferenceLines;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { getImageId } from './getImageId';
|
||||
import { addMetaData } from './metaDataProvider';
|
||||
import { OHIFError } from './classes/OHIFError';
|
||||
|
||||
let stackMap = {};
|
||||
@ -17,6 +16,7 @@ const stackUpdatedCallbacks = [];
|
||||
* @return {Array} Array with image IDs
|
||||
*/
|
||||
function createAndAddStack(stackMap, study, displaySet) {
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
const numImages = displaySet.images.length;
|
||||
const imageIds = [];
|
||||
let imageId;
|
||||
@ -38,13 +38,13 @@ function createAndAddStack(stackMap, study, displaySet) {
|
||||
metaData.frame = i;
|
||||
imageId = getImageId(image, i);
|
||||
imageIds.push(imageId);
|
||||
addMetaData(imageId, metaData);
|
||||
metadataProvider.addMetadata(imageId, metaData);
|
||||
}
|
||||
}
|
||||
else {
|
||||
imageId = getImageId(image);
|
||||
imageIds.push(imageId);
|
||||
addMetaData(imageId, metaData);
|
||||
metadataProvider.addMetadata(imageId, metaData);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -1,266 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { parsingUtils } from './parsingUtils';
|
||||
|
||||
const metaDataLookup = {};
|
||||
|
||||
/**
|
||||
* Cornerstone MetaData provider to store image meta data
|
||||
* Data from instances, series, and studies are associated with
|
||||
* imageIds to facilitate usage of this information by Cornerstone's Tools
|
||||
*
|
||||
* e.g. the imagePlane metaData object contains instance information about
|
||||
* row/column pixel spacing, patient position, and patient orientation. It
|
||||
* is used in CornerstoneTools to position reference lines and orientation markers.
|
||||
*
|
||||
* @param {String} imageId The Cornerstone ImageId
|
||||
* @param {Object} data An object containing instance, series, and study metaData
|
||||
*/
|
||||
const addMetaData = (imageId, data) => {
|
||||
let instanceMetaData = data.instance;
|
||||
let seriesMetaData = data.series;
|
||||
let studyMetaData = data.study;
|
||||
let imageIndex = data.imageIndex;
|
||||
let numImages = data.numImages;
|
||||
|
||||
let metaData = {};
|
||||
|
||||
metaData.study = {
|
||||
patientId: studyMetaData.patientId,
|
||||
studyInstanceUid: studyMetaData.studyInstanceUid,
|
||||
studyDate: studyMetaData.studyDate,
|
||||
studyTime: studyMetaData.studyTime,
|
||||
studyDescription: studyMetaData.studyDescription,
|
||||
institutionName: studyMetaData.institutionName,
|
||||
patientHistory: studyMetaData.patientHistory
|
||||
};
|
||||
|
||||
metaData.series = {
|
||||
seriesDescription: seriesMetaData.seriesDescription,
|
||||
seriesNumber: seriesMetaData.seriesNumber,
|
||||
modality: seriesMetaData.modality,
|
||||
seriesInstanceUid: seriesMetaData.seriesInstanceUid,
|
||||
numImages: numImages
|
||||
};
|
||||
|
||||
metaData.instance = instanceMetaData;
|
||||
|
||||
metaData.patient = {
|
||||
name: studyMetaData.patientName,
|
||||
id: studyMetaData.patientId,
|
||||
birthDate: studyMetaData.patientBirthDate,
|
||||
sex: studyMetaData.patientSex
|
||||
};
|
||||
|
||||
// If there is sufficient information, populate
|
||||
// the imagePlane object for easier use in the Viewer
|
||||
metaData.imagePlane = getImagePlane(instanceMetaData);
|
||||
|
||||
// Add the metaData to the imageId lookup object
|
||||
metaDataLookup[imageId] = metaData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a set of metaData to the Cornerstone metaData provider given a specific
|
||||
* imageId, type, and dataset
|
||||
*
|
||||
* @param imageId
|
||||
* @param type (e.g. series, instance, tagDisplay)
|
||||
* @param data
|
||||
*/
|
||||
const addSpecificMetadata = (imageId, type, data) => {
|
||||
let metaData = {};
|
||||
metaData[type] = data;
|
||||
|
||||
metaDataLookup[imageId] = $.extend(metaDataLookup[imageId], metaData);
|
||||
};
|
||||
|
||||
|
||||
function getFromDataSet(dataSet, type, tag) {
|
||||
if (!dataSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fn = dataSet[type];
|
||||
if (!fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
return fn.call(dataSet, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the related metaData for missing fields given a specified image
|
||||
*
|
||||
* @param image
|
||||
*/
|
||||
const updateMetaData = image => {
|
||||
const imageMetaData = metaDataLookup[image.imageId];
|
||||
if (!imageMetaData) {
|
||||
return;
|
||||
}
|
||||
|
||||
imageMetaData.instance.rows = imageMetaData.instance.rows || image.rows;
|
||||
imageMetaData.instance.columns = imageMetaData.instance.columns || image.columns;
|
||||
|
||||
imageMetaData.instance.sopClassUid = imageMetaData.instance.sopClassUid || getFromDataSet(image.data, 'string', 'x00080016');
|
||||
imageMetaData.instance.sopInstanceUid = imageMetaData.instance.sopInstanceUid || getFromDataSet(image.data, 'string', 'x00080018');
|
||||
|
||||
imageMetaData.instance.pixelSpacing = imageMetaData.instance.pixelSpacing || getFromDataSet(image.data, 'string', 'x00280030');
|
||||
imageMetaData.instance.frameOfReferenceUID = imageMetaData.instance.frameOfReferenceUID || getFromDataSet(image.data, 'string', 'x00200052');
|
||||
imageMetaData.instance.imageOrientationPatient = imageMetaData.instance.imageOrientationPatient || getFromDataSet(image.data, 'string', 'x00200037');
|
||||
imageMetaData.instance.imagePositionPatient = imageMetaData.instance.imagePositionPatient || getFromDataSet(image.data, 'string', 'x00200032');
|
||||
|
||||
imageMetaData.instance.sliceThickness = imageMetaData.instance.sliceThickness || getFromDataSet(image.data, 'string', 'x00180050');
|
||||
imageMetaData.instance.sliceLocation = imageMetaData.instance.sliceLocation || getFromDataSet(image.data, 'string', 'x00201041');
|
||||
imageMetaData.instance.tablePosition = imageMetaData.instance.tablePosition || getFromDataSet(image.data, 'string', 'x00189327');
|
||||
imageMetaData.instance.spacingBetweenSlices = imageMetaData.instance.spacingBetweenSlices || getFromDataSet(image.data, 'string', 'x00180088');
|
||||
|
||||
imageMetaData.instance.lossyImageCompression = imageMetaData.instance.lossyImageCompression || getFromDataSet(image.data, 'string', 'x00282110');
|
||||
imageMetaData.instance.lossyImageCompressionRatio = imageMetaData.instance.lossyImageCompressionRatio || getFromDataSet(image.data, 'string', 'x00282112');
|
||||
|
||||
imageMetaData.instance.frameIncrementPointer = imageMetaData.instance.frameIncrementPointer || getFromDataSet(image.data, 'string', 'x00280009');
|
||||
imageMetaData.instance.frameTime = imageMetaData.instance.frameTime || getFromDataSet(image.data, 'string', 'x00181063');
|
||||
imageMetaData.instance.frameTimeVector = imageMetaData.instance.frameTimeVector || getFromDataSet(image.data, 'string', 'x00181065');
|
||||
|
||||
if (image.data && !imageMetaData.instance.multiframeMetadata) {
|
||||
imageMetaData.instance.multiframeMetadata = getMultiframeModuleMetaData(image.data);
|
||||
}
|
||||
|
||||
imageMetaData.imagePlane = imageMetaData.imagePlane || getImagePlane(imageMetaData.instance);
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs and returns the imagePlane given the metadata instance
|
||||
*
|
||||
* @param metadataInstance The metadata instance (InstanceMetadata class) containing information to construct imagePlane
|
||||
* @returns imagePlane The constructed imagePlane to be used in viewer easily
|
||||
*/
|
||||
function getImagePlane(instance) {
|
||||
if (!instance.rows || !instance.columns || !instance.pixelSpacing ||
|
||||
!instance.frameOfReferenceUID || !instance.imageOrientationPatient ||
|
||||
!instance.imagePositionPatient) {
|
||||
return;
|
||||
}
|
||||
|
||||
const imageOrientation = instance.imageOrientationPatient.split('\\');
|
||||
const imagePosition = instance.imagePositionPatient.split('\\');
|
||||
|
||||
let columnPixelSpacing = 1.0;
|
||||
let rowPixelSpacing = 1.0;
|
||||
if (instance.pixelSpacing) {
|
||||
const split = instance.pixelSpacing.split('\\');
|
||||
rowPixelSpacing = parseFloat(split[0]);
|
||||
columnPixelSpacing = parseFloat(split[1]);
|
||||
}
|
||||
|
||||
return {
|
||||
frameOfReferenceUID:
|
||||
instance.frameOfReferenceUID,
|
||||
rows:
|
||||
instance.rows,
|
||||
columns:
|
||||
instance.columns,
|
||||
rowCosines:
|
||||
new cornerstoneMath.Vector3(parseFloat(imageOrientation[0]), parseFloat(imageOrientation[1]), parseFloat(imageOrientation[2])),
|
||||
columnCosines:
|
||||
new cornerstoneMath.Vector3(parseFloat(imageOrientation[3]), parseFloat(imageOrientation[4]), parseFloat(imageOrientation[5])),
|
||||
imagePositionPatient:
|
||||
new cornerstoneMath.Vector3(parseFloat(imagePosition[0]), parseFloat(imagePosition[1]), parseFloat(imagePosition[2])),
|
||||
rowPixelSpacing:
|
||||
rowPixelSpacing,
|
||||
columnPixelSpacing:
|
||||
columnPixelSpacing,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function extracts miltiframe information from a dicomParser.DataSet object.
|
||||
*
|
||||
* @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).
|
||||
*/
|
||||
function getMultiframeModuleMetaData(dataSet) {
|
||||
|
||||
let numberOfFrames,
|
||||
frameIncrementPointer,
|
||||
frameTime,
|
||||
frameTimeVector,
|
||||
imageInfo = {
|
||||
isMultiframeImage: false,
|
||||
frameIncrementPointer: null,
|
||||
numberOfFrames: 0,
|
||||
frameTime: 0,
|
||||
frameTimeVector: null,
|
||||
averageFrameRate: 0 // backwards compatibility only... it might be useless in the future
|
||||
};
|
||||
|
||||
if (parsingUtils.isValidDataSet(dataSet)) {
|
||||
|
||||
// (0028,0008) = Number of Frames
|
||||
numberOfFrames = dataSet.intString('x00280008', -1);
|
||||
if (numberOfFrames > 0) {
|
||||
|
||||
// set multi-frame image indicator
|
||||
imageInfo.isMultiframeImage = true;
|
||||
imageInfo.numberOfFrames = numberOfFrames;
|
||||
|
||||
// (0028,0009) = Frame Increment Pointer
|
||||
frameIncrementPointer = parsingUtils.attributeTag(dataSet, 'x00280009') || '';
|
||||
|
||||
if (frameIncrementPointer === 'x00181065') {
|
||||
// Frame Increment Pointer points to Frame Time Vector (0018,1065) field
|
||||
frameTimeVector = parsingUtils.floatArray(dataSet, 'x00181065');
|
||||
if (frameTimeVector instanceof Array && frameTimeVector.length > 0) {
|
||||
imageInfo.frameIncrementPointer = 'frameTimeVector';
|
||||
imageInfo.frameTimeVector = frameTimeVector;
|
||||
frameTime = frameTimeVector.reduce((a, b) => a + b) / frameTimeVector.length;
|
||||
imageInfo.averageFrameRate = 1000 / frameTime;
|
||||
}
|
||||
} else if (frameIncrementPointer === 'x00181063' || frameIncrementPointer === '') {
|
||||
// Frame Increment Pointer points to Frame Time (0018,1063) field or is not defined (for addtional flexibility).
|
||||
// Yet another value is possible for this field (5200,9230 for Multi-frame Functional Groups)
|
||||
// but that case is currently not supported.
|
||||
frameTime = dataSet.floatString('x00181063', -1);
|
||||
if (frameTime > 0) {
|
||||
imageInfo.frameIncrementPointer = 'frameTime';
|
||||
imageInfo.frameTime = frameTime;
|
||||
imageInfo.averageFrameRate = 1000 / frameTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return imageInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up metaData for Cornerstone Tools given a specified type and imageId
|
||||
* A type may be, e.g. 'study', or 'patient', or 'imagePlane'. These types
|
||||
* are keys in the stored metaData objects.
|
||||
*
|
||||
* @param type
|
||||
* @param imageId
|
||||
* @returns {Object} Relevant metaData of the specified type
|
||||
*/
|
||||
function provider(type, imageId) {
|
||||
let imageMetaData = metaDataLookup[imageId];
|
||||
if (!imageMetaData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (imageMetaData.hasOwnProperty(type)) {
|
||||
return imageMetaData[type];
|
||||
}
|
||||
}
|
||||
|
||||
Meteor.startup(function() {
|
||||
cornerstoneTools.metaData.addProvider(provider);
|
||||
});
|
||||
|
||||
/**
|
||||
* Export relevant symbols
|
||||
*/
|
||||
|
||||
export { addMetaData, addSpecificMetadata, updateMetaData };
|
||||
@ -1,24 +1,28 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { setInstanceClassDefaultViewportFunction } from './instanceClassSpecificViewport';
|
||||
import { addSpecificMetadata } from './metaDataProvider';
|
||||
|
||||
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
|
||||
const viewTypes = ['MLO', 'CC', 'LM', 'ML', 'XCCL'];
|
||||
const requiresInversion = ['LM']; // Tomo series are flipped
|
||||
|
||||
let instance = cornerstoneTools.metaData.get('instance', imageId);
|
||||
const instance = cornerstoneTools.metaData.get('instance', imageId);
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
let laterality = instance.laterality;
|
||||
let element = enabledElement.element;
|
||||
let position;
|
||||
const element = enabledElement.element;
|
||||
|
||||
let left = $(enabledElement.canvas).offset().left;
|
||||
let right = left + enabledElement.canvas.width;
|
||||
const left = $(enabledElement.canvas).offset().left;
|
||||
const right = left + enabledElement.canvas.width;
|
||||
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
|
||||
let laterality = instance.laterality;
|
||||
let position;
|
||||
|
||||
if (viewTypes.indexOf(instance.viewPosition) < 0) {
|
||||
return;
|
||||
@ -26,14 +30,14 @@ const setMammogramViewportAlignment = (series, enabledElement, imageId) => {
|
||||
|
||||
// Check if we should flip the laterality
|
||||
if (requiresInversion.indexOf(instance.viewPosition) > -1) {
|
||||
if (laterality === "R") {
|
||||
laterality = "L";
|
||||
} else if (laterality === "L") {
|
||||
laterality = "R";
|
||||
if (laterality === 'R') {
|
||||
laterality = 'L';
|
||||
} else if (laterality === 'L') {
|
||||
laterality = 'R';
|
||||
}
|
||||
}
|
||||
|
||||
if (laterality === "R") {
|
||||
if (laterality === 'R') {
|
||||
// Set X translation to Canvas max in image pixels - image width
|
||||
// This places it on the right side of the screen
|
||||
position = cornerstone.pageToPixel(element, right, 0);
|
||||
@ -41,7 +45,7 @@ const setMammogramViewportAlignment = (series, enabledElement, imageId) => {
|
||||
enabledElement.viewport.translation.x += position.x - enabledElement.image.width;
|
||||
}
|
||||
|
||||
addSpecificMetadata(imageId, 'tagDisplay', {
|
||||
metadataProvider.addSpecificMetadata(imageId, 'tagDisplay', {
|
||||
side: 'L'
|
||||
});
|
||||
|
||||
@ -53,7 +57,7 @@ const setMammogramViewportAlignment = (series, enabledElement, imageId) => {
|
||||
enabledElement.viewport.translation.x += position.x;
|
||||
}
|
||||
|
||||
addSpecificMetadata(imageId, 'tagDisplay', {
|
||||
metadataProvider.addSpecificMetadata(imageId, 'tagDisplay', {
|
||||
side: 'R'
|
||||
});
|
||||
}
|
||||
@ -62,7 +66,7 @@ const setMammogramViewportAlignment = (series, enabledElement, imageId) => {
|
||||
};
|
||||
|
||||
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 };
|
||||
|
||||
@ -122,7 +122,8 @@ export const toolManager = {
|
||||
configureTools() {
|
||||
// Get Cornerstone Tools
|
||||
const { panMultiTouch, textStyle, toolStyle, toolColors,
|
||||
length, arrowAnnotate, zoom, ellipticalRoi } = cornerstoneTools;
|
||||
length, arrowAnnotate, zoom, ellipticalRoi,
|
||||
textMarker, magnify } = cornerstoneTools;
|
||||
|
||||
// Set the configuration for the multitouch pan tool
|
||||
const multiTouchPanConfig = {
|
||||
@ -187,7 +188,7 @@ export const toolManager = {
|
||||
shadowOffsetX: shadowConfig.shadowOffsetX,
|
||||
shadowOffsetY: shadowConfig.shadowOffsetY
|
||||
};
|
||||
cornerstoneTools.textMarker.setConfiguration(textMarkerConfig);
|
||||
textMarker.setConfiguration(textMarkerConfig);
|
||||
|
||||
// Set the configuration values for the text annotation (Arrow) tool
|
||||
const annotateConfig = {
|
||||
@ -203,6 +204,38 @@ export const toolManager = {
|
||||
maxScale: 10
|
||||
};
|
||||
zoom.setConfiguration(zoomConfig);
|
||||
|
||||
const magnifyConfig = {
|
||||
magnifySize: 300,
|
||||
magnificationLevel: 3
|
||||
};
|
||||
magnify.setConfiguration(magnifyConfig);
|
||||
},
|
||||
/**
|
||||
* This function searches an object to return the keys that contain a specific value
|
||||
*
|
||||
* @param object {object} The object to be searched
|
||||
* @param value The value to be found
|
||||
*
|
||||
* @returns {array} The keys for which the object has the specified value
|
||||
*/
|
||||
getKeysByValue(object, value) {
|
||||
// http://stackoverflow.com/questions/9907419/javascript-object-get-key-by-value
|
||||
return Object.keys(object).filter(key => object[key] === value);
|
||||
},
|
||||
configureLoadProcess() {
|
||||
// Whenever the CornerstoneImageLoadProgress is fired, identify which viewports
|
||||
// the "in-progress" image is to be displayed in. Then pass the percent complete
|
||||
// via the Meteor Session to the other templates to be displayed in the relevant viewports.
|
||||
$(cornerstone).on('CornerstoneImageLoadProgress', (e, eventData) => {
|
||||
viewportIndices = this.getKeysByValue(window.ViewportLoading, eventData.imageId);
|
||||
viewportIndices.forEach(viewportIndex => {
|
||||
Session.set('CornerstoneLoadProgress' + viewportIndex, eventData.percentComplete);
|
||||
});
|
||||
|
||||
const encodedId = OHIF.string.encodeId(eventData.imageId);
|
||||
Session.set('CornerstoneThumbnailLoadProgress' + encodedId, eventData.percentComplete);
|
||||
});
|
||||
},
|
||||
setGestures(newGestures) {
|
||||
gestures = newGestures;
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
/**
|
||||
* Import main dependency...
|
||||
* Import main dependency
|
||||
*/
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/**
|
||||
* Create Viewerbase namespace...
|
||||
* Create Viewerbase namespace
|
||||
*/
|
||||
|
||||
const Viewerbase = {};
|
||||
|
||||
/**
|
||||
* Append Viewerbase namespace to OHIF namespace...
|
||||
* Append Viewerbase namespace to OHIF namespace
|
||||
*/
|
||||
|
||||
OHIF.viewerbase = Viewerbase;
|
||||
|
||||
/**
|
||||
* Export relevant objects...
|
||||
* Export relevant objects
|
||||
*/
|
||||
|
||||
export { OHIF, Viewerbase };
|
||||
|
||||
Loading…
Reference in New Issue
Block a user