LT-305: Add sorting function to properly order Measurement Table
This commit is contained in:
parent
0b77a1783a
commit
d6a3172bb3
@ -8,6 +8,7 @@ Template.dialogNonTargetMeasurement.onCreated(() => {
|
|||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|
||||||
instance.measurementTypeId = 'nonTargets';
|
instance.measurementTypeId = 'nonTargets';
|
||||||
|
const timepointApi = instance.data.timepointApi;
|
||||||
|
|
||||||
instance.schema = new SimpleSchema({
|
instance.schema = new SimpleSchema({
|
||||||
location: FieldLesionLocation,
|
location: FieldLesionLocation,
|
||||||
@ -16,10 +17,15 @@ Template.dialogNonTargetMeasurement.onCreated(() => {
|
|||||||
|
|
||||||
// Remove the measurement from the collection
|
// Remove the measurement from the collection
|
||||||
instance.removeMeasurement = () => {
|
instance.removeMeasurement = () => {
|
||||||
instance.viewerData.measurementApi.deleteMeasurements(instance.measurementTypeId, {
|
const measurementApi = instance.viewerData.measurementApi;
|
||||||
|
measurementApi.deleteMeasurements(instance.measurementTypeId, {
|
||||||
_id: instance.data.measurementData._id
|
_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
|
// Refresh the image with the measurement removed
|
||||||
cornerstone.updateImage(instance.data.element);
|
cornerstone.updateImage(instance.data.element);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,6 +23,7 @@ class MeasurementApi {
|
|||||||
const measurementTypeId = tool.id;
|
const measurementTypeId = tool.id;
|
||||||
|
|
||||||
this[measurementTypeId] = new Mongo.Collection(null);
|
this[measurementTypeId] = new Mongo.Collection(null);
|
||||||
|
this[measurementTypeId]._debugName = tool.name;
|
||||||
this[measurementTypeId].attachSchema(tool.schema);
|
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) {
|
deleteMeasurements(measurementTypeId, filter) {
|
||||||
const collection = this[measurementTypeId];
|
const collection = this[measurementTypeId];
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="measurementTableRow {{#unless rowItem.location}}warning{{/unless}}{{#if responseStatus}}response-status{{/if}}" data-measurementid="{{_id}}">
|
<div class="measurementTableRow {{#unless rowItem.location}}warning{{/unless}}{{#if responseStatus}}response-status{{/if}}" data-measurementid="{{_id}}">
|
||||||
<div class='measurementRowSidebar'>
|
<div class='measurementRowSidebar'>
|
||||||
<div class="measurementNumber">
|
<div class="measurementNumber">
|
||||||
{{rowItem.measurementNumber}}
|
{{rowItem.measurementNumberOverall}}
|
||||||
</div>
|
</div>
|
||||||
{{#unless rowItem.location}}
|
{{#unless rowItem.location}}
|
||||||
<div class="warning-icon">
|
<div class="warning-icon">
|
||||||
|
|||||||
@ -58,14 +58,19 @@ Template.measurementTableRow.events({
|
|||||||
const measurement = instance.data.rowItem.entries[0];
|
const measurement = instance.data.rowItem.entries[0];
|
||||||
const toolType = measurement.toolType;
|
const toolType = measurement.toolType;
|
||||||
const measurementNumber = measurement.measurementNumber;
|
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
|
// Remove all the measurements with the given type and number
|
||||||
api.deleteMeasurements(measurementTypeId, {
|
measurementApi.deleteMeasurements(measurementTypeId, {
|
||||||
toolType,
|
toolType,
|
||||||
measurementNumber
|
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
|
// Repaint the images on all viewports without the removed measurements
|
||||||
_.each($('.imageViewerViewport'), element => cornerstone.updateImage(element));
|
_.each($('.imageViewerViewport'), element => cornerstone.updateImage(element));
|
||||||
});
|
});
|
||||||
|
|||||||
@ -53,13 +53,18 @@ Template.measurementTableView.helpers({
|
|||||||
const groupObject = _.groupBy(data, entry => entry.measurementNumber);
|
const groupObject = _.groupBy(data, entry => entry.measurementNumber);
|
||||||
|
|
||||||
// Reformat the data for display in the table
|
// Reformat the data for display in the table
|
||||||
return Object.keys(groupObject).map(key => ({
|
return Object.keys(groupObject).map(key => {
|
||||||
measurementTypeId: measurementTypeId,
|
const anEntry = groupObject[key][0];
|
||||||
measurementNumber: key,
|
|
||||||
location: OHIF.measurements.getLocation(groupObject[key]),
|
return {
|
||||||
responseStatus: false, // TODO: Get the latest timepoint and determine the response status
|
measurementTypeId: measurementTypeId,
|
||||||
entries: groupObject[key]
|
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) {
|
newMeasurements(measurementType) {
|
||||||
@ -104,9 +109,12 @@ Template.measurementTableView.helpers({
|
|||||||
|
|
||||||
// Reformat the data for display in the table
|
// Reformat the data for display in the table
|
||||||
return Object.keys(groupObject).map(key => {
|
return Object.keys(groupObject).map(key => {
|
||||||
|
const anEntry = groupObject[key][0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
measurementTypeId: measurementTypeId,
|
measurementTypeId: measurementTypeId,
|
||||||
measurementNumber: key,
|
measurementNumber: key,
|
||||||
|
measurementNumberOverall: anEntry.measurementNumberOverall,
|
||||||
location: OHIF.measurements.getLocation(groupObject[key]),
|
location: OHIF.measurements.getLocation(groupObject[key]),
|
||||||
responseStatus: false, // TODO: Get the latest timepoint and determine the response status
|
responseStatus: false, // TODO: Get the latest timepoint and determine the response status
|
||||||
entries: groupObject[key]
|
entries: groupObject[key]
|
||||||
|
|||||||
@ -5,8 +5,6 @@ import { OHIF } from 'meteor/ohif:core';
|
|||||||
class MeasurementHandlers {
|
class MeasurementHandlers {
|
||||||
|
|
||||||
static onAdded(e, instance, eventData) {
|
static onAdded(e, instance, eventData) {
|
||||||
const measurementData = eventData.measurementData;
|
|
||||||
|
|
||||||
const config = OHIF.measurements.MeasurementApi.getConfiguration();
|
const config = OHIF.measurements.MeasurementApi.getConfiguration();
|
||||||
const toolTypes = config.measurementTools.map(tool => tool.cornerstoneToolType);
|
const toolTypes = config.measurementTools.map(tool => tool.cornerstoneToolType);
|
||||||
|
|
||||||
@ -15,6 +13,7 @@ class MeasurementHandlers {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const measurementData = eventData.measurementData;
|
||||||
const measurementToolConfiguration = config.measurementTools[index];
|
const measurementToolConfiguration = config.measurementTools[index];
|
||||||
const measurementApi = instance.data.measurementApi;
|
const measurementApi = instance.data.measurementApi;
|
||||||
const Collection = measurementApi[measurementToolConfiguration.id];
|
const Collection = measurementApi[measurementToolConfiguration.id];
|
||||||
@ -56,9 +55,6 @@ class MeasurementHandlers {
|
|||||||
const timepointId = timepoint.timepointId;
|
const timepointId = timepoint.timepointId;
|
||||||
measurement.timepointId = timepointId;
|
measurement.timepointId = timepointId;
|
||||||
measurement.measurementNumber = OHIF.measurements.MeasurementManager.getNewMeasurementNumber(timepointId, Collection, timepointApi);
|
measurement.measurementNumber = OHIF.measurements.MeasurementManager.getNewMeasurementNumber(timepointId, Collection, timepointApi);
|
||||||
|
|
||||||
// TODO: Fix this
|
|
||||||
measurement.measurementNumberAbsolute = measurement.measurementNumber;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const numCurrentMeasurementsInStudy = Collection.find({
|
const numCurrentMeasurementsInStudy = Collection.find({
|
||||||
@ -84,6 +80,10 @@ class MeasurementHandlers {
|
|||||||
|
|
||||||
// Insert the new measurement into the collection
|
// Insert the new measurement into the collection
|
||||||
measurementData._id = Collection.insert(measurement);
|
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) {
|
static onModified(e, instance, eventData) {
|
||||||
@ -139,6 +139,10 @@ class MeasurementHandlers {
|
|||||||
const Collection = measurementApi[measurementToolConfiguration.id];
|
const Collection = measurementApi[measurementToolConfiguration.id];
|
||||||
|
|
||||||
Collection.remove(measurementData._id);
|
Collection.remove(measurementData._id);
|
||||||
|
|
||||||
|
// Update the Overall Measurement Numbers for all Measurements
|
||||||
|
const baseline = timepointApi.baseline();
|
||||||
|
measurementApi.sortMeasurements(baseline.timepointId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,13 +4,10 @@ class MeasurementManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns new measurement number given a timepointId
|
* 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
|
// Get all current lesion measurements
|
||||||
const numMeasurements = Collection.find().count();
|
const numMeasurements = collection.find().count();
|
||||||
|
|
||||||
// If no measurements exist yet, start at 1
|
// If no measurements exist yet, start at 1
|
||||||
if (!numMeasurements) {
|
if (!numMeasurements) {
|
||||||
@ -21,7 +18,7 @@ class MeasurementManager {
|
|||||||
timepointId: timepointId
|
timepointId: timepointId
|
||||||
});
|
});
|
||||||
|
|
||||||
const numMeasurementsAtTimepoint = Collection.find({
|
const numMeasurementsAtTimepoint = collection.find({
|
||||||
studyInstanceUid: {
|
studyInstanceUid: {
|
||||||
$in: timepoint.studyInstanceUids
|
$in: timepoint.studyInstanceUids
|
||||||
}
|
}
|
||||||
@ -36,8 +33,8 @@ class MeasurementManager {
|
|||||||
* @param measurementData
|
* @param measurementData
|
||||||
* @returns {number} - Measurement location ID
|
* @returns {number} - Measurement location ID
|
||||||
*/
|
*/
|
||||||
static getLocationIdIfMeasurementExists(measurementData, Collection) {
|
static getLocationIdIfMeasurementExists(measurementData, collection) {
|
||||||
const measurement = Collection.findOne({
|
const measurement = collection.findOne({
|
||||||
measurementNumber: measurementData.measurementNumber
|
measurementNumber: measurementData.measurementNumber
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user