Improving overlay information display
This commit is contained in:
parent
c8348cc084
commit
45c5766501
@ -2,9 +2,9 @@
|
||||
<div class="imageViewerViewportOverlay noselect {{#if gt numImages 1}}controlsVisible{{/if}}">
|
||||
{{#unless tagDisplaySpecified}}
|
||||
<div class="topleft dicomTag">
|
||||
<div>{{formatPN patientName}}</div>
|
||||
<div>{{patientId}}</div>
|
||||
<div class='timepointName'>{{timepointName}}</div>
|
||||
<div>{{patientName}}</div>
|
||||
<div>{{getGenderAndAge}}</div>
|
||||
<div class="icons-section">
|
||||
{{#if linked}}
|
||||
<svg>
|
||||
@ -15,8 +15,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="topright dicomTag">
|
||||
<div>{{studyDescription}}</div>
|
||||
<div>{{formatDA studyDate}} {{formatTM studyTime}}</div>
|
||||
<div>{{seriesDescription}}</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 class="bottomright dicomTag">
|
||||
<div>{{#if zoom}}Zoom: {{formatNumberPrecision zoom 0}}%{{/if}}</div>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
// Use Aldeed's meteor-template-extension package to replace the
|
||||
@ -8,9 +10,47 @@ import { OHIF } from 'meteor/ohif:core';
|
||||
const defaultTemplate = 'viewportOverlay';
|
||||
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
|
||||
// HTML of this template is replaced with that of longitudinalViewportOverlay
|
||||
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() {
|
||||
const instance = Template.instance();
|
||||
const studyInstanceUid = instance.data.studyInstanceUid;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { cornerstone } from 'meteor/ohif:cornerstone';
|
||||
import { viewportOverlayUtils } from '../../../lib/viewportOverlayUtils';
|
||||
import { getElementIfNotEmpty } from '../../../lib/getElementIfNotEmpty';
|
||||
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);
|
||||
},
|
||||
|
||||
zoom() {
|
||||
Session.get('CornerstoneImageRendered' + this.viewportIndex);
|
||||
|
||||
@ -36,6 +39,7 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return (viewport.scale * 100.0);
|
||||
},
|
||||
|
||||
imageDimensions() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
@ -46,46 +50,55 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return image.width + ' x ' + image.height;
|
||||
},
|
||||
|
||||
patientName() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'name');
|
||||
},
|
||||
|
||||
patientId() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'id');
|
||||
},
|
||||
|
||||
patientBirthDate() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'birthDate');
|
||||
},
|
||||
|
||||
patientSex() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getPatient.call(this, 'sex');
|
||||
},
|
||||
|
||||
studyDate() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getStudy.call(this, 'studyDate');
|
||||
},
|
||||
|
||||
studyTime() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getStudy.call(this, 'studyTime');
|
||||
},
|
||||
|
||||
studyDescription() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getStudy.call(this, 'studyDescription');
|
||||
},
|
||||
|
||||
seriesDescription() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getSeries.call(this, 'seriesDescription');
|
||||
},
|
||||
|
||||
frameRate() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
@ -97,16 +110,19 @@ Template.viewportOverlay.helpers({
|
||||
const frameRate = 1000 / frameTime;
|
||||
return frameRate.toFixed(1);
|
||||
},
|
||||
|
||||
seriesNumber() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getSeries.call(this, 'seriesNumber');
|
||||
},
|
||||
|
||||
instanceNumber() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'instanceNumber');
|
||||
},
|
||||
|
||||
thickness() {
|
||||
// Displays Slice Thickness (0018,0050)
|
||||
|
||||
@ -114,6 +130,7 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'sliceThickness');
|
||||
},
|
||||
|
||||
location() {
|
||||
// Displays Slice Location (0020,1041), if present.
|
||||
// - Otherwise, displays Table Position (0018,9327)
|
||||
@ -132,6 +149,7 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'imagePositionPatient');
|
||||
},
|
||||
|
||||
spacingBetweenSlices() {
|
||||
// Displays Spacing Between Slices (0018,0088), if present.
|
||||
|
||||
@ -143,6 +161,7 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'spacingBetweenSlices');
|
||||
},
|
||||
|
||||
compression() {
|
||||
// Displays whether or not lossy compression has been applied:
|
||||
//
|
||||
@ -170,26 +189,31 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return 'Lossless / Uncompressed';
|
||||
},
|
||||
|
||||
tagDisplayLeftOnly() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'L';
|
||||
},
|
||||
|
||||
tagDisplayRightOnly() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getTagDisplay.call(this, 'side') === 'R';
|
||||
},
|
||||
|
||||
tagDisplaySpecified() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getTagDisplay.call(this, 'side');
|
||||
},
|
||||
|
||||
imageNumber() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
return viewportOverlayUtils.getInstance.call(this, 'number');
|
||||
},
|
||||
|
||||
imageIndex() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
@ -200,6 +224,7 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return stack.currentImageIdIndex + 1;
|
||||
},
|
||||
|
||||
numImages() {
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
@ -210,6 +235,7 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return stack.imageIds.length;
|
||||
},
|
||||
|
||||
prior() {
|
||||
// This helper is updated whenever a new image is displayed in the viewport
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
@ -6,6 +6,7 @@ const formatPN = context => {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
return context.replace('^', ', ');
|
||||
};
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { cornerstone } from 'meteor/ohif:cornerstone';
|
||||
import { getElementIfNotEmpty } from './getElementIfNotEmpty';
|
||||
|
||||
const getPatient = function(property) {
|
||||
@ -22,7 +23,7 @@ const getStudy = function(property) {
|
||||
if (!study) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
return study[property];
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user