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';
Session.set('TimepointsReady', false);
@ -102,5 +104,36 @@ Template.viewer.events({
},
'CornerstoneToolsMeasurementRemoved .imageViewerViewport'(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">
{{#unless this.labelAsDiv}}
<label class="wrapperLabel {{this.labelClass}}">
<label class="wrapperLabel {{this.labelClass}}" {{clone this.labelTagAttributes}}>
{{#wrapperLabelContent}}
{{>UI.contentBlock}}
{{/wrapperLabelContent}}
</label>
{{else}}
<div class="wrapperLabel {{this.labelClass}}">
<div class="wrapperLabel {{this.labelClass}}" {{clone this.labelTagAttributes}}>
{{#wrapperLabelContent}}
{{>UI.contentBlock}}
{{/wrapperLabelContent}}

View File

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

View File

@ -1,5 +1,5 @@
<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>
{{#if eq instance.state.get 'selected'}}
<div class="tree-leaf">

View File

@ -1,3 +1,4 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
import { ReactiveVar } from 'meteor/reactive-var';
@ -8,8 +9,10 @@ import { $ } from 'meteor/jquery';
Template.measureFlow.onCreated(() => {
const instance = Template.instance();
instance.value = instance.data.currentValue || '';
instance.state = new ReactiveVar('closed');
instance.description = new ReactiveVar('');
instance.description = new ReactiveVar(instance.data.currentDescription || '');
instance.descriptionEdit = new ReactiveVar(false);
const items = [
@ -76,6 +79,8 @@ Template.measureFlow.onRendered(() => {
// Make the measure flow bounded by the window borders
instance.$('.measure-flow').bounded();
instance.$('.btn-add').focus();
});
Template.measureFlow.events({
@ -84,6 +89,8 @@ Template.measureFlow.events({
},
'click .measure-flow .btn-add, click .measure-flow .btn-rename'(event, instance) {
const $measureFlow = instance.$('.measure-flow');
// Set the open state for the component
instance.state.set('open');
@ -109,10 +116,13 @@ Template.measureFlow.events({
};
// Define in which element the selectTree will be rendered in
const parentElement = instance.$('.measure-flow')[0];
const parentElement = $measureFlow[0];
// Render the selectTree element
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) {
instance.$('.measure-flow .actions').removeClass('fadeOut');
instance.descriptionEdit.set(false);
instance.$('.measure-flow').focus();
}
// 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
$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"
.measure-flow
outline: none
position: fixed
z-index: 1
&.fadeOut
animateFadeOut()
&.open,
&.selected
@ -61,7 +65,7 @@
display: none
.actions
margin-top: 16px
padding-top: 16px
opacity: 0
&:not(.fadeOut)
@ -84,7 +88,7 @@
.description
margin-top: -10px
margin-bottom: 26px
margin-bottom: 10px
textarea
background-color: white
@ -102,7 +106,7 @@
background-color: white
box-shadow: 0 10px white
line-height: 20px
margin-bottom: 26px
margin-bottom: 10px
margin-top: -10px
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 './helpers';
import './components';
import './hooks';

View File

@ -2,25 +2,43 @@ import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
import { OHIF } from 'meteor/ohif:core';
const toolMap = {
bidirectional: 'targets'
};
OHIF.measurements.toggleLabelButton = options => {
const removeButtonView = () => {
if (!options.instance.buttonView) {
return;
}
Blaze.remove(options.instance.buttonView);
options.instance.buttonView = null;
};
if (options.instance.buttonView) {
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;
};