LT-275: Storing the selected label and description on measurements collection

This commit is contained in:
Bruno Alves de Faria 2016-11-02 12:43:46 +00:00 committed by Erik Ziegler
parent 20a2a8e453
commit cd5a1277aa
10 changed files with 157 additions and 84 deletions

View File

@ -1,3 +1,5 @@
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
Session.set('TimepointsReady', false); Session.set('TimepointsReady', false);
@ -102,5 +104,36 @@ Template.viewer.events({
}, },
'CornerstoneToolsMeasurementRemoved .imageViewerViewport'(event, instance, eventData) { 'CornerstoneToolsMeasurementRemoved .imageViewerViewport'(event, instance, eventData) {
OHIF.measurements.MeasurementHandlers.onRemoved(event, instance, eventData); OHIF.measurements.MeasurementHandlers.onRemoved(event, instance, eventData);
},
CornerstoneToolsMouseClick(event, instance, data) {
const element = instance.$('.imageViewerViewport')[0];
const toolState = cornerstoneTools.getToolState(element, 'bidirectional');
// Stop here if no tool state was found
if (!toolState) {
return;
}
const selectLabelCallback = (options, value, description) => {
console.warn('>>>>options, value, description', options, value, description);
};
setTimeout(() => {
for (let i = 0; i < toolState.data.length; i++) {
const toolData = toolState.data[i];
if (toolData.active) {
OHIF.measurements.toggleLabelButton({
instance,
toolData,
element,
measurementApi: instance.data.measurementApi,
position: data.currentPoints.page,
callback: selectLabelCallback
});
break;
}
}
});
} }
}); });

View File

@ -1,12 +1,12 @@
<template name="wrapperLabel"> <template name="wrapperLabel">
{{#unless this.labelAsDiv}} {{#unless this.labelAsDiv}}
<label class="wrapperLabel {{this.labelClass}}"> <label class="wrapperLabel {{this.labelClass}}" {{clone this.labelTagAttributes}}>
{{#wrapperLabelContent}} {{#wrapperLabelContent}}
{{>UI.contentBlock}} {{>UI.contentBlock}}
{{/wrapperLabelContent}} {{/wrapperLabelContent}}
</label> </label>
{{else}} {{else}}
<div class="wrapperLabel {{this.labelClass}}"> <div class="wrapperLabel {{this.labelClass}}" {{clone this.labelTagAttributes}}>
{{#wrapperLabelContent}} {{#wrapperLabelContent}}
{{>UI.contentBlock}} {{>UI.contentBlock}}
{{/wrapperLabelContent}} {{/wrapperLabelContent}}

View File

@ -4,26 +4,26 @@ import { MeasurementSchemaTypes } from 'meteor/ohif:measurements/both/schema/mea
const CornerstoneHandleSchema = MeasurementSchemaTypes.CornerstoneHandleSchema; const CornerstoneHandleSchema = MeasurementSchemaTypes.CornerstoneHandleSchema;
const BidirectionalHandlesSchema = new SimpleSchema({ const BidirectionalHandlesSchema = new SimpleSchema({
start: { start: {
type: CornerstoneHandleSchema, type: CornerstoneHandleSchema,
label: 'Start' label: 'Start'
}, },
end: { end: {
type: CornerstoneHandleSchema, type: CornerstoneHandleSchema,
label: 'End' label: 'End'
}, },
perpendicularStart: { perpendicularStart: {
type: CornerstoneHandleSchema, type: CornerstoneHandleSchema,
label: 'Perpendicular Start' label: 'Perpendicular Start'
}, },
perpendicularEnd: { perpendicularEnd: {
type: CornerstoneHandleSchema, type: CornerstoneHandleSchema,
label: 'Perpendicular End' label: 'Perpendicular End'
}, },
textBox: { textBox: {
type: CornerstoneHandleSchema, type: CornerstoneHandleSchema,
label: 'Text Box' label: 'Text Box'
}, },
}); });
const BidirectionalSchema = new SimpleSchema([MeasurementSchemaTypes.CornerstoneToolMeasurement, { const BidirectionalSchema = new SimpleSchema([MeasurementSchemaTypes.CornerstoneToolMeasurement, {
@ -31,36 +31,46 @@ const BidirectionalSchema = new SimpleSchema([MeasurementSchemaTypes.Cornerstone
type: BidirectionalHandlesSchema, type: BidirectionalHandlesSchema,
label: 'Handles' label: 'Handles'
}, },
location: {
type: String,
label: 'Location',
optional: true
},
description: {
type: String,
label: 'Description',
optional: true
},
longestDiameter: { longestDiameter: {
type: Number, type: Number,
label: 'Longest Diameter', label: 'Longest Diameter',
decimal: true decimal: true
}, },
shortestDiameter: { shortestDiameter: {
type: Number, type: Number,
label: 'Shortest Diameter', label: 'Shortest Diameter',
decimal: true decimal: true
}, },
locationUid: { locationUid: {
type: String, type: String,
label: 'Location UID', label: 'Location UID',
optional: true // Optional because it is added after initial drawing, via a callback optional: true // Optional because it is added after initial drawing, via a callback
} }
}]); }]);
function displayFunction(data) { function displayFunction(data) {
// Check whether this is a Nodal or Extranodal Measurement // Check whether this is a Nodal or Extranodal Measurement
const targetType = 'target'; // const targetType = 'target';
const nodalType = data.isNodal ? 'nodal' : 'extraNodal'; // const nodalType = data.isNodal ? 'nodal' : 'extraNodal';
// Get criteria types // Get criteria types
const criteriaTypes = TrialCriteriaTypes.find({ // const criteriaTypes = TrialCriteriaTypes.find({
selected: true // selected: true
}).map(criteria => { // }).map(criteria => {
return criteria.id; // return criteria.id;
}); // });
const currentConstraints = OHIF.lesiontracker.getTrialCriteriaConstraints(criteriaTypes, data.imageId); // const currentConstraints = OHIF.lesiontracker.getTrialCriteriaConstraints(criteriaTypes, data.imageId);
if (data.shortestDiameter) { if (data.shortestDiameter) {
// TODO: Make this check criteria again to see if we should display // TODO: Make this check criteria again to see if we should display
@ -83,4 +93,4 @@ export const bidirectional = {
}, },
includeInCaseProgress: true, includeInCaseProgress: true,
}, },
} };

View File

@ -1,5 +1,5 @@
<template name="measureFlow"> <template name="measureFlow">
<div class="measure-flow {{#if this.threeColumns}}tree-columns{{/if}} {{instance.state.get}}" style="top:{{choose position.y 0}}px;left:{{choose position.x 0}}px"> <div class="measure-flow {{#if this.threeColumns}}tree-columns{{/if}} {{instance.state.get}}" style="top:{{choose position.y 0}}px;left:{{choose position.x 0}}px" tabindex="-1">
<button class="btn-add">Add label</button> <button class="btn-add">Add label</button>
{{#if eq instance.state.get 'selected'}} {{#if eq instance.state.get 'selected'}}
<div class="tree-leaf"> <div class="tree-leaf">

View File

@ -1,3 +1,4 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze'; import { Blaze } from 'meteor/blaze';
import { ReactiveVar } from 'meteor/reactive-var'; import { ReactiveVar } from 'meteor/reactive-var';
@ -8,8 +9,10 @@ import { $ } from 'meteor/jquery';
Template.measureFlow.onCreated(() => { Template.measureFlow.onCreated(() => {
const instance = Template.instance(); const instance = Template.instance();
instance.value = instance.data.currentValue || '';
instance.state = new ReactiveVar('closed'); instance.state = new ReactiveVar('closed');
instance.description = new ReactiveVar(''); instance.description = new ReactiveVar(instance.data.currentDescription || '');
instance.descriptionEdit = new ReactiveVar(false); instance.descriptionEdit = new ReactiveVar(false);
const items = [ const items = [
@ -76,6 +79,8 @@ Template.measureFlow.onRendered(() => {
// Make the measure flow bounded by the window borders // Make the measure flow bounded by the window borders
instance.$('.measure-flow').bounded(); instance.$('.measure-flow').bounded();
instance.$('.btn-add').focus();
}); });
Template.measureFlow.events({ Template.measureFlow.events({
@ -84,6 +89,8 @@ Template.measureFlow.events({
}, },
'click .measure-flow .btn-add, click .measure-flow .btn-rename'(event, instance) { 'click .measure-flow .btn-add, click .measure-flow .btn-rename'(event, instance) {
const $measureFlow = instance.$('.measure-flow');
// Set the open state for the component // Set the open state for the component
instance.state.set('open'); instance.state.set('open');
@ -109,10 +116,13 @@ Template.measureFlow.events({
}; };
// Define in which element the selectTree will be rendered in // Define in which element the selectTree will be rendered in
const parentElement = instance.$('.measure-flow')[0]; const parentElement = $measureFlow[0];
// Render the selectTree element // Render the selectTree element
instance.selectTreeView = Blaze.renderWithData(Template.selectTree, data, parentElement); instance.selectTreeView = Blaze.renderWithData(Template.selectTree, data, parentElement);
// Focus the measure flow to handle closing
$measureFlow.focus();
}); });
}, },
@ -149,6 +159,7 @@ Template.measureFlow.events({
if (event.which === 13 || event.which === 27) { if (event.which === 13 || event.which === 27) {
instance.$('.measure-flow .actions').removeClass('fadeOut'); instance.$('.measure-flow .actions').removeClass('fadeOut');
instance.descriptionEdit.set(false); instance.descriptionEdit.set(false);
instance.$('.measure-flow').focus();
} }
// Keep the current description if ENTER was pressed // Keep the current description if ENTER was pressed
@ -219,5 +230,31 @@ Template.measureFlow.events({
// Wait the fade-out transition and remove the selectTree component // Wait the fade-out transition and remove the selectTree component
$container.one('transitionend', event => Blaze.remove(instance.selectTreeView)); $container.one('transitionend', event => Blaze.remove(instance.selectTreeView));
},
'blur .measure-flow'(event, instance) {
const $measureFlow = $(event.currentTarget);
const element = $measureFlow[0];
Meteor.defer(() => {
const focused = $(':focus')[0];
if (element !== focused && !$.contains(element, focused)) {
$measureFlow.trigger('close');
}
});
},
'mouseout .measure-flow'(event, instance) {
const $measureFlow = $(event.currentTarget);
const canClose = instance.state.get() === 'selected' && !instance.descriptionEdit.get();
if (canClose && !$.contains($measureFlow[0], event.toElement)) {
$measureFlow.trigger('close');
}
},
'close .measure-flow'(event, instance) {
const $measureFlow = $(event.currentTarget);
$measureFlow.one('animationend', () => {
instance.data.doneCallback(instance.value.value, instance.description.get());
}).addClass('fadeOut');
} }
}); });

View File

@ -1,9 +1,13 @@
@import "{design}/app" @import "{design}/app"
.measure-flow .measure-flow
outline: none
position: fixed position: fixed
z-index: 1 z-index: 1
&.fadeOut
animateFadeOut()
&.open, &.open,
&.selected &.selected
@ -61,7 +65,7 @@
display: none display: none
.actions .actions
margin-top: 16px padding-top: 16px
opacity: 0 opacity: 0
&:not(.fadeOut) &:not(.fadeOut)
@ -84,7 +88,7 @@
.description .description
margin-top: -10px margin-top: -10px
margin-bottom: 26px margin-bottom: 10px
textarea textarea
background-color: white background-color: white
@ -102,7 +106,7 @@
background-color: white background-color: white
box-shadow: 0 10px white box-shadow: 0 10px white
line-height: 20px line-height: 20px
margin-bottom: 26px margin-bottom: 10px
margin-top: -10px margin-top: -10px
padding: 0 12px padding: 0 12px

View File

@ -1 +0,0 @@
import './viewer/imageViewerViewport.js';

View File

@ -1,27 +0,0 @@
import { Template } from 'meteor/templating';
import { OHIF } from 'meteor/ohif:core';
Template.imageViewerViewport.events({
CornerstoneToolsMouseClick(event, instance, data) {
const toolState = cornerstoneTools.getToolState(instance.element, 'bidirectional');
// Stop here if no tool state was found
if (!toolState) {
return;
}
setTimeout(() => {
for (let i = 0; i < toolState.data.length; i++) {
const toolData = toolState.data[i];
if (toolData.active) {
OHIF.measurements.toggleLabelButton({
instance,
toolData,
position: data.currentPoints.page
});
break;
}
}
});
}
});

View File

@ -1,4 +1,3 @@
import './lib'; import './lib';
import './helpers'; import './helpers';
import './components'; import './components';
import './hooks';

View File

@ -2,25 +2,43 @@ import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze'; import { Blaze } from 'meteor/blaze';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
const toolMap = {
bidirectional: 'targets'
};
OHIF.measurements.toggleLabelButton = options => { OHIF.measurements.toggleLabelButton = options => {
const removeButtonView = () => { const removeButtonView = () => {
if (!options.instance.buttonView) {
return;
}
Blaze.remove(options.instance.buttonView); Blaze.remove(options.instance.buttonView);
options.instance.buttonView = null; options.instance.buttonView = null;
}; };
if (options.instance.buttonView) { if (options.instance.buttonView) {
removeButtonView(); removeButtonView();
} else {
const data = {
position: options.position,
threeColumns: true,
hideCommon: true,
doneCallback(data) {
console.warn('>>>>DONE CALLBACK', data);
removeButtonView();
}
};
const view = Blaze.renderWithData(Template.measureFlow, data, options.instance.element);
options.instance.buttonView = view;
} }
const data = {
position: options.position,
threeColumns: true,
hideCommon: true,
doneCallback(location, description) {
options.callback(options, location, description);
const tool = toolMap[options.toolData.toolType];
options.measurementApi[tool].update(options.toolData.id, {
$set: {
location,
description
}
});
removeButtonView();
}
};
const view = Blaze.renderWithData(Template.measureFlow, data, options.element);
options.instance.buttonView = view;
}; };