diff --git a/Packages/lesiontracker/client/components/irRCDescription/irRCDescription.html b/Packages/lesiontracker/client/components/irRCDescription/irRCDescription.html
new file mode 100644
index 000000000..61c469a7f
--- /dev/null
+++ b/Packages/lesiontracker/client/components/irRCDescription/irRCDescription.html
@@ -0,0 +1,18 @@
+
+
irRC
+
Baseline Checks
+
+
Target lesions must be >= 10 X 10 mm AND >= double the acquisition slice thickness by CT and MR
+
Up to a max of 5 target lesions per organ
+
Up to a max of 10 target lesions total
+
Non-targets can only be assessed as 'present'
+
Target lesions must have measurements (cannot be assessed as CR, UN/NE, EX)
+
+
New Lesion Checks for Follow-ups
+
+
New target lesions must be >= 5 X 5 mm AND >= double the acquisition slice thickness by CT and MR
+
Up to a max of 5 target lesions per organ
+
Up to a max of 10 target lesions total
+
+
+
\ No newline at end of file
diff --git a/Packages/lesiontracker/client/components/optionsModal/optionsModal.html b/Packages/lesiontracker/client/components/optionsModal/optionsModal.html
index f8335ef9b..01ea2a6ad 100644
--- a/Packages/lesiontracker/client/components/optionsModal/optionsModal.html
+++ b/Packages/lesiontracker/client/components/optionsModal/optionsModal.html
@@ -9,58 +9,23 @@
diff --git a/Packages/lesiontracker/client/components/optionsModal/optionsModal.js b/Packages/lesiontracker/client/components/optionsModal/optionsModal.js
index 0cc2bf0b8..69df7d5d0 100644
--- a/Packages/lesiontracker/client/components/optionsModal/optionsModal.js
+++ b/Packages/lesiontracker/client/components/optionsModal/optionsModal.js
@@ -1,4 +1,24 @@
-Session.setDefault('TrialResponseAssessmentCriteria', 'RECIST');
+TrialCriteriaTypes = new Meteor.Collection(null);
+
+TrialCriteriaTypes.insert({
+ id: 'RECIST',
+ name: 'RECIST 1.1',
+ descriptionTemplate: 'recistDescription',
+ selected: true
+});
+
+TrialCriteriaTypes.insert({
+ id: 'irRC',
+ name: 'irRC',
+ descriptionTemplate: 'irRCDescription',
+ selected: false
+});
+
+Template.optionsModal.helpers({
+ trialCriteriaTypes: function() {
+ return TrialCriteriaTypes.find();
+ }
+});
Template.optionsModal.events({
/**
@@ -8,16 +28,24 @@ Template.optionsModal.events({
* @param e The 'change' event on the selected radio button
*/
'change input.trialCriteria': function(e) {
- // Get the Trial Criteria type that the selected radio button represents
- var radioButton = $(e.currentTarget);
- var criteriaType = radioButton.val();
+ var isChecked = e.currentTarget.checked;
- // Set this as the current Trial Response Assessment Criteria
- // TODO: Update when we have more trial-level support
- // (Currently this information is stored in Session, later this will change)
- Session.set('TrialResponseAssessmentCriteria', criteriaType);
+ // Set "Selected" to false for the entire collection
+ // TODO: Remove this when we allow multiple criteria
+ TrialCriteriaTypes.update({}, {
+ $set: {
+ selected: false
+ }
+ }, {
+ multi: true
+ });
- log.info('Trial Criteria changed to: ' + criteriaType);
+ // Set the current Criteria in the collection to selected
+ TrialCriteriaTypes.update(this._id, {
+ $set: {
+ selected: isChecked
+ }
+ });
},
/**
* When the Clear Study/Timepoint Associations button is clicked, we
diff --git a/Packages/lesiontracker/client/components/recistDescription/recistDescription.html b/Packages/lesiontracker/client/components/recistDescription/recistDescription.html
new file mode 100644
index 000000000..425ad597b
--- /dev/null
+++ b/Packages/lesiontracker/client/components/recistDescription/recistDescription.html
@@ -0,0 +1,14 @@
+
+
RECIST 1.1
+
Baseline Checks
+
+
Extranodal lesions must be >= 10 mm long axis AND >= double the acquisition slice thickness by CT and MR
+
Extranodal lesions must be >= 20 mm on chest x-ray (although x-rays rarely used for clinical trial assessment)
+
Nodal lesions must be >= 15 mm short axis AND >= double the acquisition slice thickness by CT and MR
+
Up to a max of 2 target lesions per organ
+
Up to a max of 5 target lesions total
+
Non-targets can only be assessed as 'present'
+
Target lesions must have measurements (cannot be assessed as CR, UN/NE, EX)
+
+
+
\ No newline at end of file
diff --git a/Packages/lesiontracker/lib/TrialCriteriaConstraints.js b/Packages/lesiontracker/lib/TrialCriteriaConstraints.js
index 7cbefa342..b8195419e 100644
--- a/Packages/lesiontracker/lib/TrialCriteriaConstraints.js
+++ b/Packages/lesiontracker/lib/TrialCriteriaConstraints.js
@@ -321,70 +321,78 @@ function irRC(image) {
* Retrieve trial criteria constraints based on the image that measurements appear upon
* If no image is specified, it is assumed that group or per Organ level criteria are desired.
*
- * @param criteriaType A valid Trial Criteria set name (e.g. 'RECIST' or 'irRC')
+ * @param criteriaTypes An array of valid Trial Criteria set names (e.g. ['RECIST', 'irRC'])
+ * NOTE: Multiple criteria are not yet supported
+ *
* @param imageId A Cornerstone Image ID
* @returns {*} An Object of Trial Criteria that can be used to validate measurements' conformance
*/
-getTrialCriteriaConstraints = function(criteriaType, imageId) {
- if (!TrialCriteriaConstraints[criteriaType]) {
- throw 'No such Trial Criteria defined: ' + criteriaType;
- }
+getTrialCriteriaConstraints = function(criteriaTypes, imageId) {
+ // TODO: update this when we allow multiple criteria
+ var allCriteria = [];
+ criteriaTypes.forEach(function(criteriaType) {
+ if (!TrialCriteriaConstraints[criteriaType]) {
+ throw 'No such Trial Criteria defined: ' + criteriaType;
+ }
- // If no imageId was specified, skip customization of the criteria
- // and return the requested criteria right away
- var criteria;
- if (!imageId) {
- criteria = TrialCriteriaConstraints[criteriaType]();
- return criteria;
- }
+ // If no imageId was specified, skip customization of the criteria
+ // and return the requested criteria right away
+ var criteria;
+ if (!imageId) {
+ criteria = TrialCriteriaConstraints[criteriaType]();
+ return criteria;
+ }
- // Otherwise, retrieve the series metaData to identify the modality of the image
- var seriesMetaData = cornerstoneTools.metaData.get('series', imageId);
- if (!seriesMetaData) {
- return;
- }
+ // Otherwise, retrieve the series metaData to identify the modality of the image
+ var seriesMetaData = cornerstoneTools.metaData.get('series', imageId);
+ if (!seriesMetaData) {
+ return;
+ }
- // TODO: Get the rest of the metaData that has already been loaded by Cornerstone
- var image = {};
+ // TODO: Get the rest of the metaData that has already been loaded by Cornerstone
+ var image = {};
- // If we are looking at an MR or CT image, we should pass the slice thickness
- // to the Trial Criteria functions so that they can customize the validation rules
- if (seriesMetaData.modality === 'MR' || seriesMetaData.modality === 'CT') {
- var instanceMetaData = cornerstoneTools.metaData.get('instance', imageId);
- image.acquisitionSliceThickness = instanceMetaData.sliceThickness;
- }
+ // If we are looking at an MR or CT image, we should pass the slice thickness
+ // to the Trial Criteria functions so that they can customize the validation rules
+ if (seriesMetaData.modality === 'MR' || seriesMetaData.modality === 'CT') {
+ var instanceMetaData = cornerstoneTools.metaData.get('instance', imageId);
+ image.acquisitionSliceThickness = instanceMetaData.sliceThickness;
+ }
- // Retrieve the study metaData in order to find the timepoint type
- var studyMetaData = cornerstoneTools.metaData.get('study', imageId);
- if (!studyMetaData) {
- return;
- }
+ // Retrieve the study metaData in order to find the timepoint type
+ var studyMetaData = cornerstoneTools.metaData.get('study', imageId);
+ if (!studyMetaData) {
+ return;
+ }
- // Retrieve the Study document from the Collection of associated Studies
- var study = Studies.findOne({
- studyInstanceUid: studyMetaData.studyInstanceUid
+ // Retrieve the Study document from the Collection of associated Studies
+ var study = Studies.findOne({
+ studyInstanceUid: studyMetaData.studyInstanceUid
+ });
+
+ if (!study) {
+ return;
+ }
+
+ // Find the related Timepoint document
+ var timepoint = Timepoints.findOne({
+ timepointId: study.timepointId
+ });
+
+ if (!timepoint) {
+ log.warn('Timepoint related to study is missing.');
+ return;
+ }
+
+ // Retrieve the Timepoint's type (e.g. 'baseline' or 'followup')
+ var timepointType = timepoint.timepointType;
+
+ // Obtain the customized trial criteria given the image metaData
+ criteria = TrialCriteriaConstraints[criteriaType](image);
+
+ // Return the relevant criteria given the current timepoint type
+ allCriteria.push(criteria[timepointType]);
});
- if (!study) {
- return;
- }
-
- // Find the related Timepoint document
- var timepoint = Timepoints.findOne({
- timepointId: study.timepointId
- });
-
- if (!timepoint) {
- log.warn('Timepoint related to study is missing.');
- return;
- }
-
- // Retrieve the Timepoint's type (e.g. 'baseline' or 'followup')
- var timepointType = timepoint.timepointType;
-
- // Obtain the customized trial criteria given the image metaData
- criteria = TrialCriteriaConstraints[criteriaType](image);
-
- // Return the relevant criteria given the current timepoint type
- return criteria[timepointType];
+ return allCriteria[0];
};
diff --git a/Packages/lesiontracker/lib/TrialResponseCriteria.js b/Packages/lesiontracker/lib/TrialResponseCriteria.js
index d8bab5dbd..bf2724443 100644
--- a/Packages/lesiontracker/lib/TrialResponseCriteria.js
+++ b/Packages/lesiontracker/lib/TrialResponseCriteria.js
@@ -70,13 +70,9 @@ function assessGroupOfMeasurements(constraints) {
type: type
});
- // Get the criteria type so we can calculate total lesion burden
- var criteriaType = Session.get('TrialResponseAssessmentCriteria');
-
// Calculate some simple group-level Measurement statistics for validation
var testStructure = {
- totalNumberOfLesions: Measurements.find().count(),
- totalLesionBurden: calculateTotalLesionBurden(criteriaType)
+ totalNumberOfLesions: Measurements.find().count()
};
// Run the conformance checks with the validate.js library
@@ -220,8 +216,12 @@ function assessSingleMeasurement(constraints, measurementData) {
function validateSingleMeasurement(measurementData) {
// Obtain the name of the current TrialResponseAssessmentCriteria that
// we are using.
- var criteriaType = Session.get('TrialResponseAssessmentCriteria');
- var currentConstraints = getTrialCriteriaConstraints(criteriaType, measurementData.imageId);
+ var criteriaTypes = TrialCriteriaTypes.find({
+ selected: true
+ }).map(function(criteria) {
+ return criteria.id;
+ });
+ var currentConstraints = getTrialCriteriaConstraints(criteriaTypes, measurementData.imageId);
// If we have no relevant constraints, stop here
if (!currentConstraints) {
@@ -264,12 +264,16 @@ function validateSingleMeasurement(measurementData) {
function validateGroups() {
log.info('validateGroups');
- // Obtain the name of the current TrialResponseAssessmentCriteria that
+ // Obtain the names of the current TrialResponseAssessmentCriteria that
// we are using.
- var criteriaType = Session.get('TrialResponseAssessmentCriteria');
-
+ var criteriaTypes = TrialCriteriaTypes.find({
+ selected: true
+ }).map(function(criteria) {
+ return criteria.id;
+ });
+
// Criteria for the specific image are retrieved from the general set of criteria.
- var currentConstraints = getTrialCriteriaConstraints(criteriaType);
+ var currentConstraints = getTrialCriteriaConstraints(criteriaTypes);
if (!currentConstraints) {
return;
}
@@ -297,10 +301,13 @@ function validateGroups() {
}
function validateAll() {
- log.info('validateAll');
- // Obtain the name of the current TrialResponseAssessmentCriteria that
+ // Obtain the names of the current TrialResponseAssessmentCriteria that
// we are using.
- var criteriaType = Session.get('TrialResponseAssessmentCriteria');
+ var criteriaTypes = TrialCriteriaTypes.find({
+ selected: true
+ }).map(function(criteria) {
+ return criteria.id;
+ });
Measurements.find().forEach(function(measurement) {
Object.keys(measurement.timepoints).forEach(function(timepointId) {
@@ -311,7 +318,7 @@ function validateAll() {
currentMeasurement._id = measurement._id;
// Criteria for the specific image are retrieved from the general set of criteria.
- var currentConstraints = getTrialCriteriaConstraints(criteriaType, currentMeasurement.imageId);
+ var currentConstraints = getTrialCriteriaConstraints(criteriaTypes, currentMeasurement.imageId);
if (!currentConstraints) {
return;
}
@@ -333,8 +340,6 @@ var validationTimeout = 400;
* @param measurementData Input measurement data from CornerstoneTools
*/
function validateDelayed(measurementData) {
- log.info('validateAllDelayed');
-
// Erase any currently-waiting validation call
clearTimeout(validationTimeout);
diff --git a/Packages/lesiontracker/package.js b/Packages/lesiontracker/package.js
index 20ea969cc..3b4112fcc 100644
--- a/Packages/lesiontracker/package.js
+++ b/Packages/lesiontracker/package.js
@@ -71,6 +71,9 @@ Package.onUse(function(api) {
api.addFiles('client/components/optionsModal/optionsModal.styl', 'client');
api.addFiles('client/components/optionsModal/optionsModal.js', 'client');
+ api.addFiles('client/components/recistDescription/recistDescription.html', 'client');
+ api.addFiles('client/components/irRCDescription/irRCDescription.html', 'client');
+
api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.html', 'client');
api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.js', 'client');
api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.styl', 'client');
@@ -201,6 +204,7 @@ Package.onUse(function(api) {
api.export('ValidationErrors', 'client');
api.export('LesionLocations', 'client');
api.export('LocationResponses', 'client');
+ api.export('TrialCriteriaTypes', 'client');
// Export collections spanning both client and server
api.export('ImageMeasurements', [ 'client', 'server' ]);