feat(measurement-table) Display support for measurements from DICOM Structured Reports (#225)
This commit is contained in:
1 parent
e9832f62f7
commit
d94f0eec16
64 files changed
+1797
-78
No files matched your search
+55
@@ -0,0 +1,55 @@
|
||||
<template name="measurementLightTableRow">
|
||||
<div class="measurementLightTableRow" data-measurementid="{{_id}}">
|
||||
<div class='measurementRowSidebar'>
|
||||
<div class="measurementNumber">
|
||||
{{rowItem.measurementNumber}}
|
||||
</div>
|
||||
{{#if rowItem.responseStatus}}
|
||||
<div class="response-status-icon">
|
||||
{{rowItem.responseStatus}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="measurementRowContent">
|
||||
<div class="measurementDetails">
|
||||
<label class="location">
|
||||
{{#if rowItem.location}}
|
||||
{{rowItem.location}}
|
||||
{{else}}
|
||||
(No Location)
|
||||
{{/if}}
|
||||
{{#if rowItem.description}}
|
||||
({{rowItem.description}})
|
||||
{{/if}}
|
||||
</label>
|
||||
<div class="value">
|
||||
{{#if displayData}}
|
||||
{{{displayData}}}
|
||||
{{else}}
|
||||
...
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rowOptions">
|
||||
<div class="rowAction js-edit-label pull-left m-r-2" tabindex="1">
|
||||
<svg class="edit-icon">
|
||||
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-measurements-additional"}}></use>
|
||||
</svg>
|
||||
Relabel
|
||||
</div>
|
||||
<div class="rowAction js-edit-description pull-left m-r-2" tabindex="1">
|
||||
<svg class="edit-icon">
|
||||
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-measurements-additional"}}></use>
|
||||
</svg>
|
||||
Description
|
||||
</div>
|
||||
<div class="rowAction js-delete pull-left" tabindex="1">
|
||||
<svg class="close-icon">
|
||||
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-ui-close"}}></use>
|
||||
</svg>
|
||||
Delete
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { cornerstone } from 'meteor/ohif:cornerstone';
|
||||
|
||||
const getPosition = event => {
|
||||
return {
|
||||
x: event.clientX,
|
||||
y: event.clientY
|
||||
};
|
||||
};
|
||||
|
||||
Template.measurementLightTableRow.helpers({
|
||||
displayData() {
|
||||
const instance = Template.instance();
|
||||
const { rowItem } = instance.data;
|
||||
|
||||
const data = rowItem.entries[0];
|
||||
|
||||
const config = OHIF.measurements.MeasurementApi.getConfiguration();
|
||||
const measurementTools = config.measurementTools;
|
||||
|
||||
const toolGroup = measurementTools.find( toolGroup => toolGroup.id === rowItem.measurementTypeId);
|
||||
const tool = toolGroup.childTools.find( childTool => childTool.id === data.toolType );
|
||||
if (!tool) {
|
||||
return 'No measurement value';
|
||||
}
|
||||
|
||||
const { displayFunction } = tool.options.measurementTable;
|
||||
return displayFunction(data);
|
||||
}
|
||||
});
|
||||
|
||||
Template.measurementLightTableRow.events({
|
||||
'click .measurementLightTableRow'(event, instance) {
|
||||
const $row = instance.$('.measurementLightTableRow');
|
||||
const rowItem = instance.data.rowItem;
|
||||
const timepoints = instance.data.timepointApi.all();
|
||||
|
||||
$row.closest('.measurementLightTableView').find('.measurementLightTableRow').not($row).removeClass('active');
|
||||
$row.toggleClass('active');
|
||||
|
||||
const childToolKey = $(event.target).attr('data-child');
|
||||
OHIF.measurements.jumpToRowItem(rowItem, timepoints, childToolKey);
|
||||
},
|
||||
|
||||
'click .js-edit-label'(event, instance) {
|
||||
event.stopPropagation();
|
||||
const rowItem = instance.data.rowItem;
|
||||
const entry = rowItem.entries[0];
|
||||
|
||||
// Show the measure flow for measurements
|
||||
OHIF.measurements.openLocationModal({
|
||||
measurement: entry,
|
||||
element: document.body,
|
||||
measurementApi: instance.data.measurementApi,
|
||||
position: getPosition(event),
|
||||
autoClick: true
|
||||
});
|
||||
},
|
||||
|
||||
'click .js-edit-description'(event, instance) {
|
||||
const rowItem = instance.data.rowItem;
|
||||
const entry = rowItem.entries[0];
|
||||
OHIF.ui.showDialog('measurementEditDescription', {
|
||||
event,
|
||||
title: 'Edit Description',
|
||||
element: event.element,
|
||||
measurementData: entry
|
||||
});
|
||||
},
|
||||
|
||||
'click .js-delete'(event, instance) {
|
||||
event.stopPropagation();
|
||||
const dialogSettings = {
|
||||
class: 'themed',
|
||||
title: 'Delete measurements',
|
||||
message: 'Are you sure you want to delete the measurement?',
|
||||
position: getPosition(event)
|
||||
};
|
||||
|
||||
OHIF.ui.showDialog('dialogConfirm', dialogSettings).then(formData => {
|
||||
const measurementTypeId = instance.data.rowItem.measurementTypeId;
|
||||
const measurement = instance.data.rowItem.entries[0];
|
||||
const measurementNumber = measurement.measurementNumber;
|
||||
const { timepointApi, measurementApi } = instance.data;
|
||||
|
||||
// Remove all the measurements with the given type and number
|
||||
measurementApi.deleteMeasurements(measurementTypeId, { measurementNumber });
|
||||
|
||||
// Sync the new measurement data with cornerstone tools
|
||||
const baseline = timepointApi.baseline();
|
||||
measurementApi.sortMeasurements(baseline.timepointId);
|
||||
|
||||
// Repaint the images on all viewports without the removed measurements
|
||||
_.each($('.imageViewerViewport'), element => cornerstone.updateImage(element));
|
||||
|
||||
// Notify that viewer suffered changes
|
||||
OHIF.measurements.triggerTimepointUnsavedChanges('deleted');
|
||||
});
|
||||
}
|
||||
});
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
@import "{ohif:design}/app"
|
||||
|
||||
.measurementLightTableRow
|
||||
display: flex
|
||||
margin-left: -6px
|
||||
margin-top: 2px
|
||||
padding-left: 6px
|
||||
opacity: 0.7
|
||||
transform(scale(1))
|
||||
width: calc(100% + 6px)
|
||||
|
||||
&:hover
|
||||
opacity 1
|
||||
|
||||
&.active
|
||||
opacity 1
|
||||
.measurementRowSidebar
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.rowOptions
|
||||
height: 35px
|
||||
visibility: visible
|
||||
|
||||
.rowOptions
|
||||
theme('background-color', '$uiGrayDarker')
|
||||
height: 0
|
||||
overflow: hidden
|
||||
transition(all 0.3s ease)
|
||||
visibility: hidden
|
||||
padding-left: 14px
|
||||
|
||||
.rowAction
|
||||
theme('color', '$defaultColor')
|
||||
cursor: pointer
|
||||
line-height: 35px
|
||||
transition(all 0.3s ease)
|
||||
|
||||
&:hover, &:active
|
||||
theme('color', '$textPrimaryColor')
|
||||
|
||||
svg
|
||||
theme('fill', '$textPrimaryColor')
|
||||
theme('stroke', '$textPrimaryColor')
|
||||
|
||||
svg
|
||||
theme('fill', '$defaultColor')
|
||||
theme('stroke', '$defaultColor')
|
||||
transition(all 0.3s ease)
|
||||
|
||||
&.edit-icon
|
||||
width: 14px
|
||||
height: 13px
|
||||
|
||||
&.close-icon
|
||||
width: 11px
|
||||
height: 11px
|
||||
|
||||
.measurementRowSidebar
|
||||
theme('background', '$uiGray')
|
||||
theme('color', '$textSecondaryColor')
|
||||
cursor: pointer
|
||||
flex: 1
|
||||
max-width: 30px
|
||||
transition(all 0.3s ease)
|
||||
|
||||
.measurementNumber
|
||||
font-size: 14px
|
||||
font-weight: 400
|
||||
margin-right: 5px
|
||||
padding-top: 10px
|
||||
text-align: center
|
||||
|
||||
.measurementRowContent
|
||||
flex: 1
|
||||
|
||||
.measurementDetails
|
||||
padding: 5px 2px 0 14px
|
||||
line-height: 30px
|
||||
font-size: 14px
|
||||
|
||||
.location
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-weight: 400
|
||||
margin-left: -2px
|
||||
|
||||
.value
|
||||
theme('color', '$textPrimaryColor')
|
||||
Reference in new issue
Block a user