LT-350: remove measurements from the viewport

This commit is contained in:
Leonardo Campos 2017-01-12 01:53:09 -02:00
parent 9a11dc1808
commit 98e8cf4eca
9 changed files with 165 additions and 78 deletions

View File

@ -3,11 +3,13 @@ import { SimpleSchema } from 'meteor/aldeed:simple-schema';
export const ToolGroupBaseSchema = new SimpleSchema({ export const ToolGroupBaseSchema = new SimpleSchema({
toolId: { toolId: {
type: String, type: String,
label: 'Tool ID' label: 'Tool ID',
optional: true
}, },
toolItemId: { toolItemId: {
type: String, type: String,
label: 'Tool Item ID' label: 'Tool Item ID',
optional: true
}, },
createdAt: { createdAt: {
type: Date type: Date

View File

@ -15,16 +15,8 @@
imageId = enabledElement.image.imageId; imageId = enabledElement.image.imageId;
} }
var enabledElements = cornerstone.getEnabledElementsByImageId(imageId); cornerstoneTools.removeToolState(element, toolType, data);
enabledElements.forEach(function(enabledElement) { cornerstone.updateImage(element);
var element = enabledElement.element;
// The HandleMeasurementRemoved handler should do the rest
cornerstoneTools.removeToolState(element, toolType, data);
//Update element
cornerstone.updateImage(element);
});
} }
// TODO = Check if we have the same function already in Cornerstone Tools // TODO = Check if we have the same function already in Cornerstone Tools
@ -32,7 +24,7 @@
var allTools = toolManager.getTools(); var allTools = toolManager.getTools();
var pointNearTool = false; var pointNearTool = false;
var touchDevice = isTouchDevice(); var touchDevice = isTouchDevice();
var nearbyTool, var nearbyTool = {},
nearbyToolIndex, nearbyToolIndex,
nearbyToolType; nearbyToolType;
@ -54,9 +46,9 @@
if (toolInterface.pointNearTool(element, data, coords)) { if (toolInterface.pointNearTool(element, data, coords)) {
pointNearTool = true; pointNearTool = true;
nearbyTool = data; nearbyTool.tool = data;
nearbyToolIndex = i; nearbyTool.index = i;
nearbyToolType = toolType; nearbyTool.toolType = toolType;
break; break;
} }
} }
@ -66,17 +58,12 @@
} }
}); });
if (pointNearTool === true) { return pointNearTool ? nearbyTool : undefined;
return {
nearbyTool: nearbyTool,
nearbyToolIndex: nearbyToolIndex,
nearbyToolType: nearbyToolType
};
}
} }
function keyDownCallback(e, eventData) { function keyDownCallback(e, eventData) {
var keyCode = eventData.which; var keyCode = eventData.which;
if (keyCode === keys.DELETE || if (keyCode === keys.DELETE ||
(keyCode === keys.D && eventData.event.ctrlKey === true)) { (keyCode === keys.D && eventData.event.ctrlKey === true)) {
@ -87,12 +74,17 @@
return; return;
} }
const dialogSettings = {
title: 'Delete measurements',
message: 'Are you sure you want to delete this measurement?'
};
// TODO= Refactor this so the confirmation dialog is an // TODO= Refactor this so the confirmation dialog is an
// optional settable callback in the tool's configuration // optional settable callback in the tool's configuration
showConfirmDialog(function() { OHIF.ui.showFormDialog('dialogConfirm', dialogSettings).then(() => {
removeMeasurementTimepoint(nearbyToolData.nearbyTool, removeMeasurementTimepoint(nearbyToolData.tool,
nearbyToolData.nearbyToolIndex, nearbyToolData.index,
nearbyToolData.nearbyToolType, nearbyToolData.toolType,
eventData.element eventData.element
); );
}); });

View File

@ -17,7 +17,7 @@ OHIF.lesiontracker.toggleLesionTrackerTools = () => {
// Hide the tools (set them all to disabled) // Hide the tools (set them all to disabled)
const toolDefaultStates = { const toolDefaultStates = {
activate: [], //'deleteLesionKeyboardTool' activate: ['deleteLesionKeyboardTool'],
deactivate: [], deactivate: [],
enable: [], enable: [],
disable: [ 'bidirectional', 'nonTarget', 'length', 'targetCR', 'targetUN', 'targetEX' ] disable: [ 'bidirectional', 'nonTarget', 'length', 'targetCR', 'targetUN', 'targetEX' ]

View File

@ -39,7 +39,7 @@ Meteor.startup(function() {
let newDefaultStates = { let newDefaultStates = {
enable: [ 'scaleOverlayTool' ], enable: [ 'scaleOverlayTool' ],
deactivate: ['bidirectional', 'nonTarget', 'length', 'targetCR', 'targetUN', 'targetEX'], deactivate: ['bidirectional', 'nonTarget', 'length', 'targetCR', 'targetUN', 'targetEX'],
activate: [] // 'deleteLesionKeyboardTool' activate: ['deleteLesionKeyboardTool']
}; };
for (let state in newDefaultStates) { for (let state in newDefaultStates) {

View File

@ -37,13 +37,37 @@ class MeasurementApi {
this.toolsGroupsMap[tool.id] = toolGroup.id; this.toolsGroupsMap[tool.id] = toolGroup.id;
const addedHandler = measurement => { const addedHandler = measurement => {
let measurementNumber;
// Get the measurement number // Get the measurement number
const timepoint = this.timepointApi.timepoints.findOne({ const timepoint = this.timepointApi.timepoints.findOne({
studyInstanceUids: measurement.studyInstanceUid studyInstanceUids: measurement.studyInstanceUid
}); });
const measurementNumber = groupCollection.find({
studyInstanceUid: { $in: timepoint.studyInstanceUids } const emptyItem = groupCollection.findOne({
}).count() + 1; toolId: { $eq: null },
timepointId: timepoint.timepointId
});
if (emptyItem) {
measurementNumber = emptyItem.measurementNumber;
groupCollection.update({
timepointId: timepoint.timepointId,
measurementNumber
}, {
$set: {
toolId: tool.id,
toolItemId: measurement._id,
createdAt: measurement.createdAt
}
});
} else {
measurementNumber = groupCollection.find({
studyInstanceUid: { $in: timepoint.studyInstanceUids }
}).count() + 1;
}
measurement.measurementNumber = measurementNumber; measurement.measurementNumber = measurementNumber;
// Get the current location (if already defined) // Get the current location (if already defined)
@ -60,16 +84,6 @@ class MeasurementApi {
} }
} }
// Reflect the entry in the tool group collection
groupCollection.insert({
toolId: tool.id,
toolItemId: measurement._id,
timepointId: timepoint.timepointId,
studyInstanceUid: measurement.studyInstanceUid,
createdAt: measurement.createdAt,
measurementNumber
});
// Set the timepoint ID, measurement number and location // Set the timepoint ID, measurement number and location
collection.update(measurement._id, { collection.update(measurement._id, {
$set: { $set: {
@ -79,39 +93,74 @@ class MeasurementApi {
} }
}); });
if (!emptyItem) {
// Reflect the entry in the tool group collection
groupCollection.insert({
toolId: tool.id,
toolItemId: measurement._id,
timepointId: timepoint.timepointId,
studyInstanceUid: measurement.studyInstanceUid,
createdAt: measurement.createdAt,
measurementNumber
});
}
// Enable reactivity // Enable reactivity
this.changeObserver.changed(); this.changeObserver.changed();
}; };
const removedHandler = measurement => { const removedHandler = measurement => {
// Remove the record from the tools group collection too const measurementNumber = measurement.measurementNumber;
groupCollection.remove({
groupCollection.update({
toolItemId: measurement._id toolItemId: measurement._id
}, {
$set: {
toolId: null,
toolItemId: null
}
}); });
// Update the measurement numbers only if it is last item const nonEmptyItem = groupCollection.findOne({
const measurementNumber = measurement.measurementNumber; measurementNumber,
const timepoint = this.timepointApi.timepoints.findOne({ toolId: { $not: null }
timepointId: measurement.timepointId
}); });
const filter = {
studyInstanceUid: { $in: timepoint.studyInstanceUids }, if (nonEmptyItem) {
measurementNumber return;
};
const remainingItems = groupCollection.find(filter).count();
if (!remainingItems) {
filter.measurementNumber = { $gte: measurementNumber };
const operator = {
$inc: { measurementNumber: -1 }
};
const options = { multi: true };
groupCollection.update(filter, operator, options);
toolGroup.childTools.forEach(childTool => {
const collection = this.tools[childTool.id];
collection.update(filter, operator, options);
});
} }
const groupItems = groupCollection.find({ measurementNumber }).fetch();
groupItems.forEach(groupItem => {
// Remove the record from the tools group collection too
groupCollection.remove({ _id: groupItem._id });
// Update the measurement numbers only if it is last item
const timepoint = this.timepointApi.timepoints.findOne({
timepointId: groupItem.timepointId
});
const filter = {
studyInstanceUid: { $in: timepoint.studyInstanceUids },
measurementNumber
};
const remainingItems = groupCollection.find(filter).count();
if (!remainingItems) {
filter.measurementNumber = { $gte: measurementNumber };
const operator = {
$inc: { measurementNumber: -1 }
};
const options = { multi: true };
groupCollection.update(filter, operator, options);
toolGroup.childTools.forEach(childTool => {
const collection = this.tools[childTool.id];
collection.update(filter, operator, options);
});
}
});
// Enable reactivity // Enable reactivity
this.changeObserver.changed(); this.changeObserver.changed();
}; };
@ -258,6 +307,8 @@ class MeasurementApi {
// Synchronize the updated measurements with Cornerstone Tools // Synchronize the updated measurements with Cornerstone Tools
// toolData to make sure the displayed measurements show 'Target X' correctly // toolData to make sure the displayed measurements show 'Target X' correctly
const syncFilter = _.clone(filter); const syncFilter = _.clone(filter);
delete syncFilter.timepointId;
syncFilter.measurementNumber = { syncFilter.measurementNumber = {
$gt: measurementNumber - 1 $gt: measurementNumber - 1
}; };
@ -281,7 +332,12 @@ class MeasurementApi {
const result = []; const result = [];
const items = this.toolGroups[toolGroupId].find(selector, options).fetch(); const items = this.toolGroups[toolGroupId].find(selector, options).fetch();
items.forEach(item => { items.forEach(item => {
result.push(this.tools[item.toolId].findOne(item.toolItemId)); if(item.toolId) {
result.push(this.tools[item.toolId].findOne(item.toolItemId));
} else {
result.push({ measurementNumber: item.measurementNumber });
}
}); });
return result; return result;
} }

View File

@ -124,7 +124,6 @@ class TimepointApi {
}); });
} }
// Return the prior timepoint
lock() { lock() {
const current = this.current(); const current = this.current();
if (!current) { if (!current) {
@ -138,6 +137,7 @@ class TimepointApi {
}); });
} }
// Return the prior timepoint
prior() { prior() {
const current = this.current(); const current = this.current();
if (!current) { if (!current) {

View File

@ -70,17 +70,40 @@ Template.measurementTableTimepointCell.events({
const rowItem = instance.data.rowItem; const rowItem = instance.data.rowItem;
const timepoints = instance.data.timepoints.get(); const timepoints = instance.data.timepoints.get();
OHIF.measurements.jumpToRowItem(rowItem, timepoints); OHIF.measurements.jumpToRowItem(rowItem, timepoints);
}/*, },
'keydown .measurementTableTimepointCell'(event, instance) { 'keydown .measurementTableTimepointCell'(event, instance) {
const keyCode = event.which; const keyCode = event.which;
if (keyCode === keys.DELETE ||
(keyCode === keys.D && e.ctrlKey === true)) {
const currentMeasurement = Template.parentData(1).rowItem;
const currentTimepointID = this.timepointId;
showConfirmDialog(function() { if (keyCode === keys.DELETE || keyCode === keys.BACKSPACE || (keyCode === keys.D && event.ctrlKey === true)) {
OHIF.lesiontracker.clearMeasurementTimepointData(currentMeasurement._id, currentTimepointID); const currentMeasurement = Template.parentData(1).rowItem;
const timepointId = this.timepointId;
const dialogSettings = {
title: 'Delete measurements',
message: 'Are you sure you want to delete this measurement?'
};
OHIF.ui.showFormDialog('dialogConfirm', dialogSettings).then(() => {
const measurementTypeId = instance.data.rowItem.measurementTypeId;
const measurement = instance.data.rowItem.entries[0];
const measurementNumber = measurement.measurementNumber;
const measurementApi = instance.data.measurementApi;
const timepointApi = instance.data.timepointApi;
// Remove all the measurements with the given type and number
measurementApi.deleteMeasurements(measurementTypeId, {
measurementNumber,
timepointId
});
// 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));
}); });
} }
}*/ }
}); });

View File

@ -4,7 +4,6 @@
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness) theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
theme('color', '$textPrimaryColor') theme('color', '$textPrimaryColor')
padding: 0 10px padding: 0 10px
outline: none
cursor: pointer cursor: pointer
&:hover &:hover

View File

@ -114,11 +114,26 @@ class MeasurementHandlers {
static onRemoved(e, instance, eventData) { static onRemoved(e, instance, eventData) {
OHIF.log.info('CornerstoneToolsMeasurementRemoved'); OHIF.log.info('CornerstoneToolsMeasurementRemoved');
const measurementData = eventData.measurementData; const measurementData = eventData.measurementData;
const measurementNumber = measurementData.measurementNumber;
const measurementApi = instance.data.measurementApi; const measurementApi = instance.data.measurementApi;
const Collection = measurementApi.tools[eventData.toolType]; const timepointApi = instance.data.timepointApi;
const collection = measurementApi.tools[eventData.toolType];
const measurementTypeId = measurementApi.toolsGroupsMap[measurementData.toolType];
const measurement = collection.findOne(measurementData._id);
const timepointId = measurement.timepointId;
// Remove the measurement from the collection // Remove all the measurements with the given type and number
Collection.remove(measurementData._id); measurementApi.deleteMeasurements(measurementTypeId, {
measurementNumber,
timepointId
});
// 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));
// Signal unsaved changes // Signal unsaved changes
OHIF.ui.unsavedChanges.set('viewer.studyViewer.measurements.' + eventData.toolType); OHIF.ui.unsavedChanges.set('viewer.studyViewer.measurements.' + eventData.toolType);