Creating ohif:metadata package with metadata classes and adding it to the viewers
This commit is contained in:
parent
30a50c7ade
commit
660b828f4b
@ -35,6 +35,7 @@ ohif:dicom-services
|
||||
ohif:hanging-protocols
|
||||
ohif:user-management
|
||||
ohif:lesiontracker
|
||||
ohif:metadata
|
||||
|
||||
accounts-base@1.2.14
|
||||
accounts-password@1.3.3
|
||||
|
||||
@ -95,6 +95,7 @@ ohif:hanging-protocols@0.0.1
|
||||
ohif:lesiontracker@0.0.1
|
||||
ohif:log@0.0.1
|
||||
ohif:measurements@0.0.1
|
||||
ohif:metadata@0.0.1
|
||||
ohif:study-list@0.0.1
|
||||
ohif:user-management@0.0.1
|
||||
ohif:viewerbase@0.0.1
|
||||
|
||||
@ -13,6 +13,7 @@ ohif:study-list
|
||||
ohif:dicom-services
|
||||
ohif:hanging-protocols
|
||||
# ohif:user-management
|
||||
ohif:metadata
|
||||
|
||||
twbs:bootstrap
|
||||
http@1.2.10
|
||||
|
||||
@ -20,10 +20,6 @@ caching-compiler@1.1.9
|
||||
caching-html-compiler@1.0.7
|
||||
callback-hook@1.0.10
|
||||
check@1.2.4
|
||||
clinical:router@2.0.17
|
||||
clinical:router-location@2.0.14
|
||||
clinical:router-middleware-stack@2.0.13
|
||||
clinical:router-url@2.0.15
|
||||
coffeescript@1.11.1_4
|
||||
ddp@1.2.5
|
||||
ddp-client@1.3.2
|
||||
@ -81,6 +77,7 @@ ohif:design@0.0.1
|
||||
ohif:dicom-services@0.0.1
|
||||
ohif:hanging-protocols@0.0.1
|
||||
ohif:log@0.0.1
|
||||
ohif:metadata@0.0.1
|
||||
ohif:study-list@0.0.1
|
||||
ohif:viewerbase@0.0.1
|
||||
ohif:wadoproxy@0.0.1
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
|
||||
Template.toolbarSection.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
@ -182,7 +183,7 @@ Template.toolbarSection.helpers({
|
||||
title: 'CINE',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-youtube-play',
|
||||
disableFunction: Viewerbase.viewportUtils.hasMultipleFrames
|
||||
disableFunction: OHIF.viewerbase.viewportUtils.hasMultipleFrames
|
||||
});
|
||||
}
|
||||
|
||||
@ -232,11 +233,11 @@ Template.toolbarSection.onRendered(function() {
|
||||
instance.$('#layout').dropdown();
|
||||
|
||||
if (OHIF.uiSettings.displayEchoUltrasoundWorkflow) {
|
||||
Viewerbase.viewportUtils.toggleCineDialog();
|
||||
toggleCineDialog();
|
||||
}
|
||||
|
||||
// Set disabled/enabled tool buttons that are set in toolManager
|
||||
const states = Viewerbase.toolManager.getToolDefaultStates();
|
||||
const states = OHIF.viewerbase.toolManager.getToolDefaultStates();
|
||||
const disabledToolButtons = states.disabledToolButtons;
|
||||
const allToolbarButtons = $('#toolbar').find('button');
|
||||
if (disabledToolButtons && disabledToolButtons.length > 0) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
import 'meteor/ohif:metadata';
|
||||
|
||||
OHIF.viewer = OHIF.viewer || {};
|
||||
OHIF.viewer.defaultTool = 'wwwc';
|
||||
@ -54,6 +55,8 @@ Template.viewer.onCreated(() => {
|
||||
instance.data.studies.forEach(study => {
|
||||
study.selected = true;
|
||||
study.displaySets = Viewerbase.createStacks(study);
|
||||
// const studyMetadata = new OHIF.metadata.StudyMetadata(study);
|
||||
// study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata);
|
||||
ViewerStudies.insert(study);
|
||||
ViewerData[contentId].studyInstanceUids.push(study.studyInstanceUid);
|
||||
});
|
||||
|
||||
@ -26,7 +26,6 @@ Package.onUse(function(api) {
|
||||
// Both client & server
|
||||
api.addFiles('both/namespace.js');
|
||||
api.addFiles('both/collections.js');
|
||||
//api.addFiles('both/dicomTagDescriptions.js');
|
||||
api.addFiles('both/schema.js');
|
||||
api.addFiles('both/hardcodedData.js');
|
||||
api.addFiles('both/testData.js');
|
||||
|
||||
58
Packages/ohif-metadata/client/OHIFInstanceMetadata.js
Normal file
58
Packages/ohif-metadata/client/OHIFInstanceMetadata.js
Normal file
@ -0,0 +1,58 @@
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
|
||||
const InstanceMetadata = Viewerbase.metadata.InstanceMetadata;
|
||||
|
||||
export class OHIFInstanceMetadata extends InstanceMetadata {
|
||||
|
||||
/**
|
||||
* @param {Object} Instance object.
|
||||
*/
|
||||
constructor(data) {
|
||||
super(data);
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const data = this.getData();
|
||||
// set protected property...
|
||||
this._sopInstanceUID = data.sopInstanceUid;
|
||||
}
|
||||
|
||||
// Override
|
||||
getRawValue(tagOrProperty, defaultValue) {
|
||||
const propertyName = OHIFInstanceMetadata.getPropertyName(tagOrProperty);
|
||||
|
||||
const data = this.getData();
|
||||
const rawValue = data[propertyName];
|
||||
|
||||
return rawValue !== void 0 ? rawValue : defaultValue;
|
||||
}
|
||||
|
||||
// Override
|
||||
tagExists(tagOrProperty) {
|
||||
const propertyName = OHIFInstanceMetadata.getPropertyName(tagOrProperty);
|
||||
|
||||
const data = this.getData();
|
||||
|
||||
return (propertyName in data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static methods
|
||||
*/
|
||||
|
||||
static getPropertyName(tagOrProperty) {
|
||||
const tagInfo = InstanceMetadata.getTagInfo(tagOrProperty);
|
||||
|
||||
if(tagInfo.propertyName === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let propertyName = tagInfo.propertyName.charAt(0).toLowerCase() + tagInfo.propertyName.substr(1);
|
||||
// TODO: Improve this: change retriveMetadata to use dicom standard names (see dicomTagDescriptions.js)
|
||||
propertyName = propertyName.replace(/^sop/, 'SOP');
|
||||
propertyName = propertyName.replace(/uid$/i, 'UID');
|
||||
|
||||
return propertyName;
|
||||
}
|
||||
}
|
||||
26
Packages/ohif-metadata/client/OHIFSeriesMetadata.js
Normal file
26
Packages/ohif-metadata/client/OHIFSeriesMetadata.js
Normal file
@ -0,0 +1,26 @@
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
import { OHIFInstanceMetadata } from './OHIFInstanceMetadata';
|
||||
|
||||
export class OHIFSeriesMetadata extends Viewerbase.metadata.SeriesMetadata {
|
||||
|
||||
/**
|
||||
* @param {Object} Series object.
|
||||
*/
|
||||
constructor(data) {
|
||||
super(data);
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const data = this.getData();
|
||||
|
||||
// set protected property...
|
||||
this._seriesInstanceUID = data.seriesInstanceUid;
|
||||
// populate internal list of instances...
|
||||
data.instances.forEach(instance => {
|
||||
this.addInstance(new OHIFInstanceMetadata(instance));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
Packages/ohif-metadata/client/OHIFStudyMetadata.js
Normal file
25
Packages/ohif-metadata/client/OHIFStudyMetadata.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
import { OHIFSeriesMetadata } from './OHIFSeriesMetadata';
|
||||
|
||||
export class OHIFStudyMetadata extends Viewerbase.metadata.StudyMetadata {
|
||||
|
||||
/**
|
||||
* @param {Object} Study object.
|
||||
*/
|
||||
constructor(data) {
|
||||
super(data);
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const data = this.getData();
|
||||
|
||||
// set protected property...
|
||||
this._studyInstanceUID = data.studyInstanceUid;
|
||||
// populate internal list of series...
|
||||
data.seriesList.forEach(series => {
|
||||
this.addSeries(new OHIFSeriesMetadata(series));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
10
Packages/ohif-metadata/client/index.js
Normal file
10
Packages/ohif-metadata/client/index.js
Normal file
@ -0,0 +1,10 @@
|
||||
import { Metadata } from '../namespace';
|
||||
|
||||
// OHIFStudyMetadata, OHIFSeriesMetadata, OHIFInstanceMetadata
|
||||
import { OHIFStudyMetadata } from './OHIFStudyMetadata';
|
||||
import { OHIFSeriesMetadata } from './OHIFSeriesMetadata';
|
||||
import { OHIFInstanceMetadata } from './OHIFInstanceMetadata';
|
||||
|
||||
Metadata.StudyMetadata = OHIFStudyMetadata;
|
||||
Metadata.SeriesMetadata = OHIFSeriesMetadata;
|
||||
Metadata.InstanceMetadata = OHIFInstanceMetadata;
|
||||
39
Packages/ohif-metadata/main.js
Normal file
39
Packages/ohif-metadata/main.js
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Import namespace...
|
||||
*/
|
||||
|
||||
import { OHIF, Metadata } from './namespace.js';
|
||||
|
||||
/**
|
||||
* Import scripts that will populate the Metadata namespace as a side effect only import. This is effectively the public API...
|
||||
*/
|
||||
|
||||
import './client/'; // which is actually: import './client/index.js';
|
||||
|
||||
/**
|
||||
* Export relevant objects...
|
||||
*
|
||||
* With the following export it becomes possible to import "OHIF" from "ohif:core" and "Metadata"
|
||||
* from "ohif:metadata" using a single import (a shorthand), like this:
|
||||
*
|
||||
* import { OHIF } from 'meteor/ohif:metadata';
|
||||
*
|
||||
* Which is equivalent to:
|
||||
*
|
||||
* import { OHIF } from 'meteor/ohif:core';
|
||||
* import 'meteor/ohif:metadata';
|
||||
*
|
||||
* The second (extended) format should be used when other OHIF packages are also to be used within
|
||||
* the current module. This makes it explicit that the following imports will populate their
|
||||
* respective namespaces within the to "OHIF" namespace. Example:
|
||||
*
|
||||
* import { OHIF } from 'meteor/ohif:core';
|
||||
* import 'meteor/ohif:metadata';
|
||||
* import 'meteor/ohif:hanging-protocols';
|
||||
* [ ... ]
|
||||
* OHIF.metadata.setActiveViewport(...);
|
||||
* OHIF.hangingprotocols.doSomething(...);
|
||||
*
|
||||
*/
|
||||
|
||||
export { OHIF, Metadata };
|
||||
23
Packages/ohif-metadata/namespace.js
Normal file
23
Packages/ohif-metadata/namespace.js
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Import main dependency...
|
||||
*/
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/**
|
||||
* Create Metadata namespace...
|
||||
*/
|
||||
|
||||
const Metadata = {};
|
||||
|
||||
/**
|
||||
* Append Metadata namespace to OHIF namespace...
|
||||
*/
|
||||
|
||||
OHIF.metadata = Metadata;
|
||||
|
||||
/**
|
||||
* Export relevant objects...
|
||||
*/
|
||||
|
||||
export { OHIF, Metadata };
|
||||
16
Packages/ohif-metadata/package.js
Normal file
16
Packages/ohif-metadata/package.js
Normal file
@ -0,0 +1,16 @@
|
||||
Package.describe({
|
||||
name: 'ohif:metadata',
|
||||
summary: 'OHIF Metadata classes',
|
||||
version: '0.0.1'
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
api.versionsFrom('1.4');
|
||||
|
||||
api.use('ecmascript');
|
||||
|
||||
api.use('ohif:core');
|
||||
api.use('ohif:viewerbase');
|
||||
|
||||
api.mainModule('main.js', 'client');
|
||||
});
|
||||
@ -1,5 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
|
||||
// Define the StudyMetaData object. This is used as a cache
|
||||
// to store study meta data information to prevent unnecessary
|
||||
@ -56,7 +56,7 @@ getStudyMetadata = function(studyInstanceUid, doneCallback, failCallback) {
|
||||
|
||||
// Once we have retrieved the data, we sort the series' by series
|
||||
// and instance number in ascending order
|
||||
Viewerbase.sortStudy(study);
|
||||
OHIF.viewerbase.sortStudy(study);
|
||||
|
||||
// Add additional metadata to our study from the studylist
|
||||
var studylistStudy = StudyListStudies.findOne({
|
||||
|
||||
@ -119,7 +119,7 @@ function resultDataToStudyMetadata(studyInstanceUid, resultData) {
|
||||
laterality: instance[0x00200062],
|
||||
viewPosition: instance[0x00185101],
|
||||
acquisitionDatetime: instance[0x0008002A],
|
||||
numFrames: parseFloat(instance[0x00280008]),
|
||||
numberOfFrames: parseFloat(instance[0x00280008]),
|
||||
frameIncrementPointer: getValue(instance[0x00280009]),
|
||||
frameTime: parseFloat(instance[0x00181063]),
|
||||
frameTimeVector: parseFloatArray(instance[0x00181065]),
|
||||
|
||||
@ -97,7 +97,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
||||
laterality: remoteGetValue(instance['0020,0062']),
|
||||
viewPosition: remoteGetValue(instance['0018,5101']),
|
||||
acquisitionDatetime: remoteGetValue(instance['0008,002A']),
|
||||
numFrames: parseFloat(remoteGetValue(instance['0028,0008'])),
|
||||
numberOfFrames: parseFloat(remoteGetValue(instance['0028,0008'])),
|
||||
frameIncrementPointer: remoteGetValue(instance['0028,0009']),
|
||||
frameTime: parseFloat(remoteGetValue(instance['0018,1063'])),
|
||||
frameTimeVector: parseFloatArray(remoteGetValue(instance['0018,1065']))
|
||||
|
||||
@ -109,7 +109,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
||||
laterality: DICOMWeb.getString(instance['00200062']),
|
||||
viewPosition: DICOMWeb.getString(instance['00185101']),
|
||||
acquisitionDatetime: DICOMWeb.getString(instance['0008002A']),
|
||||
numFrames: DICOMWeb.getNumber(instance['00280008']),
|
||||
numberOfFrames: DICOMWeb.getNumber(instance['00280008']),
|
||||
frameIncrementPointer: DICOMWeb.getAttribute(instance['00280009']),
|
||||
frameTime: DICOMWeb.getNumber(instance['00181063']),
|
||||
frameTimeVector: parseFloatArray(DICOMWeb.getString(instance['00181065'])),
|
||||
|
||||
@ -163,6 +163,10 @@ Viewerbase.helpers = helpers;
|
||||
import { sopClassDictionary } from './lib/sopClassDictionary';
|
||||
Viewerbase.sopClassDictionary = sopClassDictionary;
|
||||
|
||||
// dicomTagDescriptions
|
||||
import { dicomTagDescriptions } from './lib/dicomTagDescriptions';
|
||||
Viewerbase.dicomTagDescriptions = dicomTagDescriptions;
|
||||
|
||||
/**
|
||||
* Exported Classes
|
||||
*/
|
||||
|
||||
@ -30,10 +30,10 @@ function createAndAddStack(stackMap, study, displaySet) {
|
||||
imageIndex: imageIndex + 1
|
||||
};
|
||||
|
||||
const numFrames = image.numFrames;
|
||||
if (numFrames > 1) {
|
||||
const numberOfFrames = image.numberOfFrames;
|
||||
if (numberOfFrames > 1) {
|
||||
OHIF.log.info('Multiframe image detected');
|
||||
for (let i = 0; i < numFrames; i++) {
|
||||
for (let i = 0; i < numberOfFrames; i++) {
|
||||
metaData.frame = i;
|
||||
imageId = getImageId(image, i);
|
||||
imageIds.push(imageId);
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Metadata } from './Metadata';
|
||||
import { dicomTagDescriptions } from '../../dicomTagDescriptions';
|
||||
|
||||
const UNDEFINED = 'undefined';
|
||||
const NUMBER = 'number';
|
||||
const STRING = 'string';
|
||||
const REGEX_TAG = /^x[0-9a-f]{8}$/;
|
||||
const REGEX_TAG = /^x[0-9a-fx]{8}$/;
|
||||
|
||||
export class InstanceMetadata extends Metadata {
|
||||
|
||||
@ -132,7 +133,17 @@ export class InstanceMetadata extends Metadata {
|
||||
propertyName = tagOrProperty;
|
||||
}
|
||||
|
||||
// @TODO: map tagName to propertyName and vice versa
|
||||
// It's a property
|
||||
if (tagName === null) {
|
||||
for (let tag in dicomTagDescriptions) {
|
||||
if (dicomTagDescriptions[tag] === propertyName) {
|
||||
tagName = tag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (propertyName === null) {
|
||||
propertyName = dicomTagDescriptions[tagName] || null;
|
||||
}
|
||||
|
||||
return { tagName, propertyName };
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ function createStacks(study) {
|
||||
displaySet.setAttributes({
|
||||
isClip: true,
|
||||
studyInstanceUid: study.studyInstanceUid, // Include the study instance Uid for drag/drop purposes
|
||||
numImageFrames: instance.numFrames, // Override the default value of instances.length
|
||||
numImageFrames: instance.numberOfFrames, // Override the default value of instances.length
|
||||
instanceNumber: instance.instanceNumber, // Include the instance number
|
||||
acquisitionDatetime: instance.acquisitionDatetime // Include the acquisition datetime
|
||||
});
|
||||
@ -110,7 +110,7 @@ function isSingleImageModality(modality) {
|
||||
}
|
||||
|
||||
function isMultiFrame(instance) {
|
||||
return instance.numFrames > 1;
|
||||
return instance.numberOfFrames > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
HP.tagDescriptions = {
|
||||
export const dicomTagDescriptions = {
|
||||
x00020000: 'FileMetaInfoGroupLength',
|
||||
x00020001: 'FileMetaInfoVersion',
|
||||
x00020002: 'MediaStorageSOPClassUID',
|
||||
@ -3145,4 +3145,4 @@ HP.tagDescriptions = {
|
||||
xfffee000: 'StartOfItem',
|
||||
xfffee00d: 'EndOfItems',
|
||||
xfffee0dd: 'EndOfSequence'
|
||||
};
|
||||
};
|
||||
@ -126,7 +126,6 @@ const stackOfInstancesToDisplaySets = (sopInstances, seriesView) => {
|
||||
const groups = _.groupBy(sopInstances, sopInstance => {
|
||||
// Create an empty string to store our key
|
||||
let result = '';
|
||||
const instanceView = sopInstance.getData();
|
||||
|
||||
// For each rule, find out if the tag exists
|
||||
seriesSplittingRules.forEach(rule => {
|
||||
@ -134,8 +133,8 @@ const stackOfInstancesToDisplaySets = (sopInstances, seriesView) => {
|
||||
result += ';'
|
||||
|
||||
// If the tag exists, concatenate its value to our key
|
||||
if (instanceView.exists(rule.tag)) {
|
||||
result += instanceView.raw(rule.tag);
|
||||
if (sopInstance.tagExists(rule.tag)) {
|
||||
result += sopInstance.getRawValue(rule.tag);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user