From 98e8cf4eca866f553b1c9910aed8dd1cfd7a2b29 Mon Sep 17 00:00:00 2001 From: Leonardo Campos Date: Thu, 12 Jan 2017 01:53:09 -0200 Subject: [PATCH] LT-350: remove measurements from the viewport --- .../configuration/toolGroups/baseSchema.js | 6 +- .../compatibility/deleteLesionKeyboardTool.js | 42 +++--- .../client/lib/toggleLesionTrackerTools.js | 2 +- Packages/ohif-lesiontracker/client/tools.js | 2 +- .../both/configuration/measurements.js | 128 +++++++++++++----- .../both/configuration/timepoints.js | 2 +- .../measurementTableTimepointCell.js | 39 ++++-- .../measurementTableTimepointCell.styl | 1 - .../client/lib/MeasurementHandlers.js | 21 ++- 9 files changed, 165 insertions(+), 78 deletions(-) diff --git a/Packages/ohif-lesiontracker/both/configuration/toolGroups/baseSchema.js b/Packages/ohif-lesiontracker/both/configuration/toolGroups/baseSchema.js index dbd53d65b..22576a52c 100644 --- a/Packages/ohif-lesiontracker/both/configuration/toolGroups/baseSchema.js +++ b/Packages/ohif-lesiontracker/both/configuration/toolGroups/baseSchema.js @@ -3,11 +3,13 @@ import { SimpleSchema } from 'meteor/aldeed:simple-schema'; export const ToolGroupBaseSchema = new SimpleSchema({ toolId: { type: String, - label: 'Tool ID' + label: 'Tool ID', + optional: true }, toolItemId: { type: String, - label: 'Tool Item ID' + label: 'Tool Item ID', + optional: true }, createdAt: { type: Date diff --git a/Packages/ohif-lesiontracker/client/compatibility/deleteLesionKeyboardTool.js b/Packages/ohif-lesiontracker/client/compatibility/deleteLesionKeyboardTool.js index f30b6c7d4..347717df0 100644 --- a/Packages/ohif-lesiontracker/client/compatibility/deleteLesionKeyboardTool.js +++ b/Packages/ohif-lesiontracker/client/compatibility/deleteLesionKeyboardTool.js @@ -15,16 +15,8 @@ imageId = enabledElement.image.imageId; } - var enabledElements = cornerstone.getEnabledElementsByImageId(imageId); - enabledElements.forEach(function(enabledElement) { - var element = enabledElement.element; - - // The HandleMeasurementRemoved handler should do the rest - cornerstoneTools.removeToolState(element, toolType, data); - - //Update element - cornerstone.updateImage(element); - }); + cornerstoneTools.removeToolState(element, toolType, data); + cornerstone.updateImage(element); } // TODO = Check if we have the same function already in Cornerstone Tools @@ -32,7 +24,7 @@ var allTools = toolManager.getTools(); var pointNearTool = false; var touchDevice = isTouchDevice(); - var nearbyTool, + var nearbyTool = {}, nearbyToolIndex, nearbyToolType; @@ -54,9 +46,9 @@ if (toolInterface.pointNearTool(element, data, coords)) { pointNearTool = true; - nearbyTool = data; - nearbyToolIndex = i; - nearbyToolType = toolType; + nearbyTool.tool = data; + nearbyTool.index = i; + nearbyTool.toolType = toolType; break; } } @@ -66,17 +58,12 @@ } }); - if (pointNearTool === true) { - return { - nearbyTool: nearbyTool, - nearbyToolIndex: nearbyToolIndex, - nearbyToolType: nearbyToolType - }; - } + return pointNearTool ? nearbyTool : undefined; } function keyDownCallback(e, eventData) { var keyCode = eventData.which; + if (keyCode === keys.DELETE || (keyCode === keys.D && eventData.event.ctrlKey === true)) { @@ -87,12 +74,17 @@ 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 // optional settable callback in the tool's configuration - showConfirmDialog(function() { - removeMeasurementTimepoint(nearbyToolData.nearbyTool, - nearbyToolData.nearbyToolIndex, - nearbyToolData.nearbyToolType, + OHIF.ui.showFormDialog('dialogConfirm', dialogSettings).then(() => { + removeMeasurementTimepoint(nearbyToolData.tool, + nearbyToolData.index, + nearbyToolData.toolType, eventData.element ); }); diff --git a/Packages/ohif-lesiontracker/client/lib/toggleLesionTrackerTools.js b/Packages/ohif-lesiontracker/client/lib/toggleLesionTrackerTools.js index b884567c0..fadfacf45 100644 --- a/Packages/ohif-lesiontracker/client/lib/toggleLesionTrackerTools.js +++ b/Packages/ohif-lesiontracker/client/lib/toggleLesionTrackerTools.js @@ -17,7 +17,7 @@ OHIF.lesiontracker.toggleLesionTrackerTools = () => { // Hide the tools (set them all to disabled) const toolDefaultStates = { - activate: [], //'deleteLesionKeyboardTool' + activate: ['deleteLesionKeyboardTool'], deactivate: [], enable: [], disable: [ 'bidirectional', 'nonTarget', 'length', 'targetCR', 'targetUN', 'targetEX' ] diff --git a/Packages/ohif-lesiontracker/client/tools.js b/Packages/ohif-lesiontracker/client/tools.js index a223885de..e1dcdacdf 100644 --- a/Packages/ohif-lesiontracker/client/tools.js +++ b/Packages/ohif-lesiontracker/client/tools.js @@ -39,7 +39,7 @@ Meteor.startup(function() { let newDefaultStates = { enable: [ 'scaleOverlayTool' ], deactivate: ['bidirectional', 'nonTarget', 'length', 'targetCR', 'targetUN', 'targetEX'], - activate: [] // 'deleteLesionKeyboardTool' + activate: ['deleteLesionKeyboardTool'] }; for (let state in newDefaultStates) { diff --git a/Packages/ohif-measurements/both/configuration/measurements.js b/Packages/ohif-measurements/both/configuration/measurements.js index 4e723c81e..8cc228a02 100644 --- a/Packages/ohif-measurements/both/configuration/measurements.js +++ b/Packages/ohif-measurements/both/configuration/measurements.js @@ -37,13 +37,37 @@ class MeasurementApi { this.toolsGroupsMap[tool.id] = toolGroup.id; const addedHandler = measurement => { + let measurementNumber; + // Get the measurement number const timepoint = this.timepointApi.timepoints.findOne({ studyInstanceUids: measurement.studyInstanceUid }); - const measurementNumber = groupCollection.find({ - studyInstanceUid: { $in: timepoint.studyInstanceUids } - }).count() + 1; + + const emptyItem = groupCollection.findOne({ + 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; // 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 collection.update(measurement._id, { $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 this.changeObserver.changed(); }; const removedHandler = measurement => { - // Remove the record from the tools group collection too - groupCollection.remove({ + const measurementNumber = measurement.measurementNumber; + + groupCollection.update({ toolItemId: measurement._id + }, { + $set: { + toolId: null, + toolItemId: null + } }); - // Update the measurement numbers only if it is last item - const measurementNumber = measurement.measurementNumber; - const timepoint = this.timepointApi.timepoints.findOne({ - timepointId: measurement.timepointId + const nonEmptyItem = groupCollection.findOne({ + measurementNumber, + toolId: { $not: null } }); - 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); - }); + + if (nonEmptyItem) { + return; } + 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 this.changeObserver.changed(); }; @@ -258,6 +307,8 @@ class MeasurementApi { // Synchronize the updated measurements with Cornerstone Tools // toolData to make sure the displayed measurements show 'Target X' correctly const syncFilter = _.clone(filter); + delete syncFilter.timepointId; + syncFilter.measurementNumber = { $gt: measurementNumber - 1 }; @@ -281,7 +332,12 @@ class MeasurementApi { const result = []; const items = this.toolGroups[toolGroupId].find(selector, options).fetch(); 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; } diff --git a/Packages/ohif-measurements/both/configuration/timepoints.js b/Packages/ohif-measurements/both/configuration/timepoints.js index 946ce29e9..8dd63c752 100644 --- a/Packages/ohif-measurements/both/configuration/timepoints.js +++ b/Packages/ohif-measurements/both/configuration/timepoints.js @@ -124,7 +124,6 @@ class TimepointApi { }); } - // Return the prior timepoint lock() { const current = this.current(); if (!current) { @@ -138,6 +137,7 @@ class TimepointApi { }); } + // Return the prior timepoint prior() { const current = this.current(); if (!current) { diff --git a/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.js b/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.js index 51d1f69bc..e4fe28371 100644 --- a/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.js +++ b/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.js @@ -70,17 +70,40 @@ Template.measurementTableTimepointCell.events({ const rowItem = instance.data.rowItem; const timepoints = instance.data.timepoints.get(); OHIF.measurements.jumpToRowItem(rowItem, timepoints); - }/*, + }, + 'keydown .measurementTableTimepointCell'(event, instance) { 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() { - OHIF.lesiontracker.clearMeasurementTimepointData(currentMeasurement._id, currentTimepointID); + if (keyCode === keys.DELETE || keyCode === keys.BACKSPACE || (keyCode === keys.D && event.ctrlKey === true)) { + 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)); }); } - }*/ + } }); diff --git a/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.styl b/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.styl index f897f85e1..a59331991 100644 --- a/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.styl +++ b/Packages/ohif-measurements/client/components/measurementTable/measurementTableTimepointCell/measurementTableTimepointCell.styl @@ -4,7 +4,6 @@ theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness) theme('color', '$textPrimaryColor') padding: 0 10px - outline: none cursor: pointer &:hover diff --git a/Packages/ohif-measurements/client/lib/MeasurementHandlers.js b/Packages/ohif-measurements/client/lib/MeasurementHandlers.js index de747fc5c..3c1b90a57 100644 --- a/Packages/ohif-measurements/client/lib/MeasurementHandlers.js +++ b/Packages/ohif-measurements/client/lib/MeasurementHandlers.js @@ -114,11 +114,26 @@ class MeasurementHandlers { static onRemoved(e, instance, eventData) { OHIF.log.info('CornerstoneToolsMeasurementRemoved'); const measurementData = eventData.measurementData; + const measurementNumber = measurementData.measurementNumber; 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 - Collection.remove(measurementData._id); + // 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)); // Signal unsaved changes OHIF.ui.unsavedChanges.set('viewer.studyViewer.measurements.' + eventData.toolType);