From d6a3172bb3a982c4e7dbb4142d1406246f9b9141 Mon Sep 17 00:00:00 2001 From: Erik Ziegler Date: Tue, 15 Nov 2016 15:02:38 +0100 Subject: [PATCH] LT-305: Add sorting function to properly order Measurement Table --- .../components/dialog/nonTargetMeasurement.js | 8 +- .../both/configuration/measurements.js | 105 ++++++++++++++++++ .../measurementTableRow.html | 2 +- .../measurementTableRow.js | 9 +- .../measurementTableView.js | 22 ++-- .../client/lib/MeasurementHandlers.js | 14 ++- .../client/lib/MeasurementManager.js | 15 +-- 7 files changed, 150 insertions(+), 25 deletions(-) diff --git a/Packages/ohif-lesiontracker/client/components/dialog/nonTargetMeasurement.js b/Packages/ohif-lesiontracker/client/components/dialog/nonTargetMeasurement.js index 4e279a753..95b592d16 100644 --- a/Packages/ohif-lesiontracker/client/components/dialog/nonTargetMeasurement.js +++ b/Packages/ohif-lesiontracker/client/components/dialog/nonTargetMeasurement.js @@ -8,6 +8,7 @@ Template.dialogNonTargetMeasurement.onCreated(() => { const instance = Template.instance(); instance.measurementTypeId = 'nonTargets'; + const timepointApi = instance.data.timepointApi; instance.schema = new SimpleSchema({ location: FieldLesionLocation, @@ -16,10 +17,15 @@ Template.dialogNonTargetMeasurement.onCreated(() => { // Remove the measurement from the collection instance.removeMeasurement = () => { - instance.viewerData.measurementApi.deleteMeasurements(instance.measurementTypeId, { + const measurementApi = instance.viewerData.measurementApi; + measurementApi.deleteMeasurements(instance.measurementTypeId, { _id: instance.data.measurementData._id }); + // Update the Overall Measurement Numbers for all Measurements + const baseline = timepointApi.baseline(); + measurementApi.sortMeasurements(baseline.timepointId); + // Refresh the image with the measurement removed cornerstone.updateImage(instance.data.element); }; diff --git a/Packages/ohif-measurements/both/configuration/measurements.js b/Packages/ohif-measurements/both/configuration/measurements.js index 893a4f85b..4e7326ca8 100644 --- a/Packages/ohif-measurements/both/configuration/measurements.js +++ b/Packages/ohif-measurements/both/configuration/measurements.js @@ -23,6 +23,7 @@ class MeasurementApi { const measurementTypeId = tool.id; this[measurementTypeId] = new Mongo.Collection(null); + this[measurementTypeId]._debugName = tool.name; this[measurementTypeId].attachSchema(tool.schema); }); } @@ -90,6 +91,110 @@ class MeasurementApi { }); } + // TODO: Create a better function to combine hasDataAtTimepoint and hasNoDataAtTimepoint + // because this doesn't seem very elegant... + hasDataAtTimepoint(collection, timepointId) { + // Retrieve all the data for this Measurement type (e.g. 'targets') + // which was recorded at baseline. + const dataAtTimepoint = collection.find({timepointId}); + + // Obtain a list of the Measurement Numbers from the + // measurements which have data at this timepoint + const numbers = dataAtTimepoint.map(m => m.measurementNumber); + + // Retrieve all the data for this Measurement type which + // match the Measurement Numbers obtained above + const filter = { + measurementNumber: { + $in: numbers + } + }; + + return collection.find(filter).fetch(); + } + + hasNoDataAtTimepoint(collection, timepointId) { + // Retrieve all the data for this Measurement type (e.g. 'targets') + // which was recorded at baseline. + const dataAtTimepoint = collection.find({timepointId}); + + // Obtain a list of the Measurement Numbers from the + // measurements which have data at this timepoint + const numbers = dataAtTimepoint.map(m => m.measurementNumber); + + // Retrieve all the data for this Measurement type which + // match the Measurement Numbers obtained above + const filter = { + measurementNumber: { + $nin: numbers + } + }; + + return collection.find(filter).fetch(); + } + + sortMeasurements(baselineTimepointId) { + const tools = configuration.measurementTools; + const hasDataAtTimepoint = this.hasDataAtTimepoint; + const hasNoDataAtTimepoint = this.hasNoDataAtTimepoint; + + const includedTools = tools.filter(tool => { + return (tool.options && tool.options.includeInCaseProgress === true); + }); + + let overallMeasurementNumber = 1; + + // Given a Collection and a + const updateMeasurementNumberOverall = (collection, toolType) => { + return data => { + const filter = { + measurementNumber: data.measurementNumber, + toolType + } + + collection.update(filter, { + $set: { + measurementNumberOverall: overallMeasurementNumber + } + }); + + // Increment the overall measurement number + overallMeasurementNumber += 1; + }; + }; + + const summarizeMeasurement = (groupObject, toolType) => { + return key => { + return { + measurementNumber: parseInt(key, 10), + entries: groupObject[key], + toolType + }; + }; + }; + + // First, handle data that has a measurement at baseline + includedTools.forEach(tool => { + const collection = this[tool.id]; + const toolType = tool.cornerstoneToolType; + const measurements = hasDataAtTimepoint(collection, baselineTimepointId); + const groupObject = _.groupBy(measurements, m => m.measurementNumber); + const sortedByMeasurementNumber = Object.keys(groupObject).map(summarizeMeasurement(groupObject, toolType)); + sortedByMeasurementNumber.forEach(updateMeasurementNumberOverall(collection, toolType)) + }); + + // Next, handle New Measurements (i.e. no baseline data) + // Note that this cannot be combined with the loop above due to the incrementing of the overallMeasurementNumber + includedTools.forEach(tool => { + const collection = this[tool.id]; + const toolType = tool.cornerstoneToolType; + const measurements = hasNoDataAtTimepoint(collection, baselineTimepointId); + const groupObject = _.groupBy(measurements, m => m.measurementNumber); + const sortedByMeasurementNumber = Object.keys(groupObject).map(summarizeMeasurement(groupObject, toolType)); + sortedByMeasurementNumber.forEach(updateMeasurementNumberOverall(collection, toolType)); + }); + } + deleteMeasurements(measurementTypeId, filter) { const collection = this[measurementTypeId]; diff --git a/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.html b/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.html index 2fb1a6f9e..ebbc6a8ca 100644 --- a/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.html +++ b/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.html @@ -2,7 +2,7 @@
- {{rowItem.measurementNumber}} + {{rowItem.measurementNumberOverall}}
{{#unless rowItem.location}}
diff --git a/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.js b/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.js index 54457b9fe..92d6f14d2 100644 --- a/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.js +++ b/Packages/ohif-measurements/client/components/measurementTable/measurementTableRow/measurementTableRow.js @@ -58,14 +58,19 @@ Template.measurementTableRow.events({ const measurement = instance.data.rowItem.entries[0]; const toolType = measurement.toolType; const measurementNumber = measurement.measurementNumber; - const api = instance.data.measurementApi; + const measurementApi = instance.data.measurementApi; + const timepointApi = instance.data.timepointApi; // Remove all the measurements with the given type and number - api.deleteMeasurements(measurementTypeId, { + measurementApi.deleteMeasurements(measurementTypeId, { toolType, measurementNumber }); + // Update the Overall Measurement Numbers for all Measurements + 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/measurementTableView/measurementTableView.js b/Packages/ohif-measurements/client/components/measurementTable/measurementTableView/measurementTableView.js index 4330abd55..c502ce3dc 100644 --- a/Packages/ohif-measurements/client/components/measurementTable/measurementTableView/measurementTableView.js +++ b/Packages/ohif-measurements/client/components/measurementTable/measurementTableView/measurementTableView.js @@ -53,13 +53,18 @@ Template.measurementTableView.helpers({ const groupObject = _.groupBy(data, entry => entry.measurementNumber); // Reformat the data for display in the table - return Object.keys(groupObject).map(key => ({ - measurementTypeId: measurementTypeId, - measurementNumber: key, - location: OHIF.measurements.getLocation(groupObject[key]), - responseStatus: false, // TODO: Get the latest timepoint and determine the response status - entries: groupObject[key] - })); + return Object.keys(groupObject).map(key => { + const anEntry = groupObject[key][0]; + + return { + measurementTypeId: measurementTypeId, + measurementNumber: key, + measurementNumberOverall: anEntry.measurementNumberOverall, + location: OHIF.measurements.getLocation(groupObject[key]), + responseStatus: false, // TODO: Get the latest timepoint and determine the response status + entries: groupObject[key] + }; + }); }, newMeasurements(measurementType) { @@ -104,9 +109,12 @@ Template.measurementTableView.helpers({ // Reformat the data for display in the table return Object.keys(groupObject).map(key => { + const anEntry = groupObject[key][0]; + return { measurementTypeId: measurementTypeId, measurementNumber: key, + measurementNumberOverall: anEntry.measurementNumberOverall, location: OHIF.measurements.getLocation(groupObject[key]), responseStatus: false, // TODO: Get the latest timepoint and determine the response status entries: groupObject[key] diff --git a/Packages/ohif-measurements/client/lib/MeasurementHandlers.js b/Packages/ohif-measurements/client/lib/MeasurementHandlers.js index c08b47203..076989e6e 100644 --- a/Packages/ohif-measurements/client/lib/MeasurementHandlers.js +++ b/Packages/ohif-measurements/client/lib/MeasurementHandlers.js @@ -5,8 +5,6 @@ import { OHIF } from 'meteor/ohif:core'; class MeasurementHandlers { static onAdded(e, instance, eventData) { - const measurementData = eventData.measurementData; - const config = OHIF.measurements.MeasurementApi.getConfiguration(); const toolTypes = config.measurementTools.map(tool => tool.cornerstoneToolType); @@ -15,6 +13,7 @@ class MeasurementHandlers { return; } + const measurementData = eventData.measurementData; const measurementToolConfiguration = config.measurementTools[index]; const measurementApi = instance.data.measurementApi; const Collection = measurementApi[measurementToolConfiguration.id]; @@ -56,9 +55,6 @@ class MeasurementHandlers { const timepointId = timepoint.timepointId; measurement.timepointId = timepointId; measurement.measurementNumber = OHIF.measurements.MeasurementManager.getNewMeasurementNumber(timepointId, Collection, timepointApi); - - // TODO: Fix this - measurement.measurementNumberAbsolute = measurement.measurementNumber; } } else { const numCurrentMeasurementsInStudy = Collection.find({ @@ -84,6 +80,10 @@ class MeasurementHandlers { // Insert the new measurement into the collection measurementData._id = Collection.insert(measurement); + + // Update the Overall Measurement Numbers for all Measurements + const baseline = timepointApi.baseline(); + measurementApi.sortMeasurements(baseline.timepointId); } static onModified(e, instance, eventData) { @@ -139,6 +139,10 @@ class MeasurementHandlers { const Collection = measurementApi[measurementToolConfiguration.id]; Collection.remove(measurementData._id); + + // Update the Overall Measurement Numbers for all Measurements + const baseline = timepointApi.baseline(); + measurementApi.sortMeasurements(baseline.timepointId); } } diff --git a/Packages/ohif-measurements/client/lib/MeasurementManager.js b/Packages/ohif-measurements/client/lib/MeasurementManager.js index a43718b31..79d7bb048 100644 --- a/Packages/ohif-measurements/client/lib/MeasurementManager.js +++ b/Packages/ohif-measurements/client/lib/MeasurementManager.js @@ -4,13 +4,10 @@ class MeasurementManager { /** * Returns new measurement number given a timepointId - * @param timepointId - * @param isTarget - * @returns {number} - Number of measurements in timepoint */ - static getNewMeasurementNumber(timepointId, Collection, timepointApi) { + static getNewMeasurementNumber(timepointId, collection, timepointApi) { // Get all current lesion measurements - const numMeasurements = Collection.find().count(); + const numMeasurements = collection.find().count(); // If no measurements exist yet, start at 1 if (!numMeasurements) { @@ -21,7 +18,7 @@ class MeasurementManager { timepointId: timepointId }); - const numMeasurementsAtTimepoint = Collection.find({ + const numMeasurementsAtTimepoint = collection.find({ studyInstanceUid: { $in: timepoint.studyInstanceUids } @@ -36,8 +33,8 @@ class MeasurementManager { * @param measurementData * @returns {number} - Measurement location ID */ - static getLocationIdIfMeasurementExists(measurementData, Collection) { - const measurement = Collection.findOne({ + static getLocationIdIfMeasurementExists(measurementData, collection) { + const measurement = collection.findOne({ measurementNumber: measurementData.measurementNumber }); @@ -50,4 +47,4 @@ class MeasurementManager { } -OHIF.measurements.MeasurementManager = MeasurementManager; +OHIF.measurements.MeasurementManager = MeasurementManager; \ No newline at end of file