LT-350: remove measurements from the viewport
This commit is contained in:
parent
9a11dc1808
commit
98e8cf4eca
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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' ]
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user