Improving overlay information display

This commit is contained in:
Bruno Alves de Faria 2018-01-30 16:46:31 -02:00
parent c8348cc084
commit 45c5766501
5 changed files with 76 additions and 5 deletions

View File

@ -2,9 +2,9 @@
<div class="imageViewerViewportOverlay noselect {{#if gt numImages 1}}controlsVisible{{/if}}"> <div class="imageViewerViewportOverlay noselect {{#if gt numImages 1}}controlsVisible{{/if}}">
{{#unless tagDisplaySpecified}} {{#unless tagDisplaySpecified}}
<div class="topleft dicomTag"> <div class="topleft dicomTag">
<div>{{formatPN patientName}}</div>
<div>{{patientId}}</div> <div>{{patientId}}</div>
<div class='timepointName'>{{timepointName}}</div> <div>{{patientName}}</div>
<div>{{getGenderAndAge}}</div>
<div class="icons-section"> <div class="icons-section">
{{#if linked}} {{#if linked}}
<svg> <svg>
@ -15,8 +15,11 @@
</div> </div>
</div> </div>
<div class="topright dicomTag"> <div class="topright dicomTag">
<div>{{studyDescription}}</div> <div>{{seriesDescription}}</div>
<div>{{formatDA studyDate}} {{formatTM studyTime}}</div> <div>{{studyInfo 'AccessionNumber'}}</div>
<div>{{formatDA (studyInfo 'AcquisitionDate')}} {{formatTM (studyInfo 'AcquisitionTime')}}</div>
<div>{{#if seriesNumber}}S: {{seriesNumber}}{{#if gt numImages 1}},{{/if}}{{/if}} {{#if gt numImages 1}}I: {{instanceNumber}} ({{imageIndex}}/{{numImages}}){{/if}}</div>
<div class='timepointName'>{{timepointName}}</div>
</div> </div>
<div class="bottomright dicomTag"> <div class="bottomright dicomTag">
<div>{{#if zoom}}Zoom: {{formatNumberPrecision zoom 0}}%{{/if}}</div> <div>{{#if zoom}}Zoom: {{formatNumberPrecision zoom 0}}%{{/if}}</div>

View File

@ -1,5 +1,7 @@
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { Session } from 'meteor/session'; import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';
import { ReactiveVar } from 'meteor/reactive-var';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
// Use Aldeed's meteor-template-extension package to replace the // Use Aldeed's meteor-template-extension package to replace the
@ -8,9 +10,47 @@ import { OHIF } from 'meteor/ohif:core';
const defaultTemplate = 'viewportOverlay'; const defaultTemplate = 'viewportOverlay';
Template.longitudinalViewportOverlay.replaces(defaultTemplate); Template.longitudinalViewportOverlay.replaces(defaultTemplate);
Template[defaultTemplate].onCreated(() => {
const instance = Template.instance();
instance.instanceMetadata = new ReactiveVar();
const { DICOMTagDescriptions } = OHIF.viewerbase;
instance.getValueByTagKeyword = tagKeyword => {
const instanceMetadata = instance.instanceMetadata.get();
const tagObject = DICOMTagDescriptions.find(tagKeyword);
if (!instanceMetadata || !tagObject) return;
return instanceMetadata.getRawValue(tagObject.tag);
};
// Run this computation every time the image is changed
Tracker.autorun(() => {
Session.get('CornerstoneNewImage' + instance.data.viewportIndex);
const { studyInstanceUid, seriesInstanceUid, currentImageIdIndex } = instance.data;
OHIF.studies.loadStudy(studyInstanceUid).then(studyMetadata => {
const seriesMetadata = studyMetadata.getSeriesByUID(seriesInstanceUid);
const instanceMetadata = seriesMetadata.getInstanceByIndex(currentImageIdIndex);
instance.instanceMetadata.set(instanceMetadata);
});
});
});
// Add the TimepointName helper to the default template. The // Add the TimepointName helper to the default template. The
// HTML of this template is replaced with that of longitudinalViewportOverlay // HTML of this template is replaced with that of longitudinalViewportOverlay
Template[defaultTemplate].helpers({ Template[defaultTemplate].helpers({
studyInfo(tagKeyword) {
const instance = Template.instance();
instance.instanceMetadata.dep.depend();
return instance.getValueByTagKeyword(tagKeyword);
},
getGenderAndAge() {
const instance = Template.instance();
const values = [];
values.push(instance.getValueByTagKeyword('PatientSex'));
values.push(instance.getValueByTagKeyword('PatientAge'));
return values.filter(value => !!value).join(', ');
},
timepointName() { timepointName() {
const instance = Template.instance(); const instance = Template.instance();
const studyInstanceUid = instance.data.studyInstanceUid; const studyInstanceUid = instance.data.studyInstanceUid;

View File

@ -1,6 +1,8 @@
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { Session } from 'meteor/session'; import { Session } from 'meteor/session';
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
import { cornerstone } from 'meteor/ohif:cornerstone';
import { viewportOverlayUtils } from '../../../lib/viewportOverlayUtils'; import { viewportOverlayUtils } from '../../../lib/viewportOverlayUtils';
import { getElementIfNotEmpty } from '../../../lib/getElementIfNotEmpty'; import { getElementIfNotEmpty } from '../../../lib/getElementIfNotEmpty';
import { getStackDataIfNotEmpty } from '../../../lib/getStackDataIfNotEmpty'; import { getStackDataIfNotEmpty } from '../../../lib/getStackDataIfNotEmpty';
@ -21,6 +23,7 @@ Template.viewportOverlay.helpers({
return 'W ' + viewport.voi.windowWidth.toFixed(0) + ' L ' + viewport.voi.windowCenter.toFixed(0); return 'W ' + viewport.voi.windowWidth.toFixed(0) + ' L ' + viewport.voi.windowCenter.toFixed(0);
}, },
zoom() { zoom() {
Session.get('CornerstoneImageRendered' + this.viewportIndex); Session.get('CornerstoneImageRendered' + this.viewportIndex);
@ -36,6 +39,7 @@ Template.viewportOverlay.helpers({
return (viewport.scale * 100.0); return (viewport.scale * 100.0);
}, },
imageDimensions() { imageDimensions() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
@ -46,46 +50,55 @@ Template.viewportOverlay.helpers({
return image.width + ' x ' + image.height; return image.width + ' x ' + image.height;
}, },
patientName() { patientName() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getPatient.call(this, 'name'); return viewportOverlayUtils.getPatient.call(this, 'name');
}, },
patientId() { patientId() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getPatient.call(this, 'id'); return viewportOverlayUtils.getPatient.call(this, 'id');
}, },
patientBirthDate() { patientBirthDate() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getPatient.call(this, 'birthDate'); return viewportOverlayUtils.getPatient.call(this, 'birthDate');
}, },
patientSex() { patientSex() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getPatient.call(this, 'sex'); return viewportOverlayUtils.getPatient.call(this, 'sex');
}, },
studyDate() { studyDate() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getStudy.call(this, 'studyDate'); return viewportOverlayUtils.getStudy.call(this, 'studyDate');
}, },
studyTime() { studyTime() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getStudy.call(this, 'studyTime'); return viewportOverlayUtils.getStudy.call(this, 'studyTime');
}, },
studyDescription() { studyDescription() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getStudy.call(this, 'studyDescription'); return viewportOverlayUtils.getStudy.call(this, 'studyDescription');
}, },
seriesDescription() { seriesDescription() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getSeries.call(this, 'seriesDescription'); return viewportOverlayUtils.getSeries.call(this, 'seriesDescription');
}, },
frameRate() { frameRate() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
@ -97,16 +110,19 @@ Template.viewportOverlay.helpers({
const frameRate = 1000 / frameTime; const frameRate = 1000 / frameTime;
return frameRate.toFixed(1); return frameRate.toFixed(1);
}, },
seriesNumber() { seriesNumber() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getSeries.call(this, 'seriesNumber'); return viewportOverlayUtils.getSeries.call(this, 'seriesNumber');
}, },
instanceNumber() { instanceNumber() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getInstance.call(this, 'instanceNumber'); return viewportOverlayUtils.getInstance.call(this, 'instanceNumber');
}, },
thickness() { thickness() {
// Displays Slice Thickness (0018,0050) // Displays Slice Thickness (0018,0050)
@ -114,6 +130,7 @@ Template.viewportOverlay.helpers({
return viewportOverlayUtils.getInstance.call(this, 'sliceThickness'); return viewportOverlayUtils.getInstance.call(this, 'sliceThickness');
}, },
location() { location() {
// Displays Slice Location (0020,1041), if present. // Displays Slice Location (0020,1041), if present.
// - Otherwise, displays Table Position (0018,9327) // - Otherwise, displays Table Position (0018,9327)
@ -132,6 +149,7 @@ Template.viewportOverlay.helpers({
return viewportOverlayUtils.getInstance.call(this, 'imagePositionPatient'); return viewportOverlayUtils.getInstance.call(this, 'imagePositionPatient');
}, },
spacingBetweenSlices() { spacingBetweenSlices() {
// Displays Spacing Between Slices (0018,0088), if present. // Displays Spacing Between Slices (0018,0088), if present.
@ -143,6 +161,7 @@ Template.viewportOverlay.helpers({
return viewportOverlayUtils.getInstance.call(this, 'spacingBetweenSlices'); return viewportOverlayUtils.getInstance.call(this, 'spacingBetweenSlices');
}, },
compression() { compression() {
// Displays whether or not lossy compression has been applied: // Displays whether or not lossy compression has been applied:
// //
@ -170,26 +189,31 @@ Template.viewportOverlay.helpers({
return 'Lossless / Uncompressed'; return 'Lossless / Uncompressed';
}, },
tagDisplayLeftOnly() { tagDisplayLeftOnly() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'L'; return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'L';
}, },
tagDisplayRightOnly() { tagDisplayRightOnly() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'R'; return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'R';
}, },
tagDisplaySpecified() { tagDisplaySpecified() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getTagDisplay.call(this, 'side'); return viewportOverlayUtils.getTagDisplay.call(this, 'side');
}, },
imageNumber() { imageNumber() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
return viewportOverlayUtils.getInstance.call(this, 'number'); return viewportOverlayUtils.getInstance.call(this, 'number');
}, },
imageIndex() { imageIndex() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
@ -200,6 +224,7 @@ Template.viewportOverlay.helpers({
return stack.currentImageIdIndex + 1; return stack.currentImageIdIndex + 1;
}, },
numImages() { numImages() {
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);
@ -210,6 +235,7 @@ Template.viewportOverlay.helpers({
return stack.imageIds.length; return stack.imageIds.length;
}, },
prior() { prior() {
// This helper is updated whenever a new image is displayed in the viewport // This helper is updated whenever a new image is displayed in the viewport
Session.get('CornerstoneNewImage' + this.viewportIndex); Session.get('CornerstoneNewImage' + this.viewportIndex);

View File

@ -6,6 +6,7 @@ const formatPN = context => {
if (!context) { if (!context) {
return; return;
} }
return context.replace('^', ', '); return context.replace('^', ', ');
}; };

View File

@ -1,3 +1,4 @@
import { cornerstone } from 'meteor/ohif:cornerstone';
import { getElementIfNotEmpty } from './getElementIfNotEmpty'; import { getElementIfNotEmpty } from './getElementIfNotEmpty';
const getPatient = function(property) { const getPatient = function(property) {
@ -22,7 +23,7 @@ const getStudy = function(property) {
if (!study) { if (!study) {
return ''; return '';
} }
return study[property]; return study[property];
}; };