Add some WIP changes to Lesion Tracker dialogs
This commit is contained in:
parent
e4c24608af
commit
da197368bf
@ -51,12 +51,6 @@ Template.viewer.onCreated(function() {
|
|||||||
}
|
}
|
||||||
OHIF.viewer.isPlaying[viewportIndex] = !OHIF.viewer.isPlaying[viewportIndex];
|
OHIF.viewer.isPlaying[viewportIndex] = !OHIF.viewer.isPlaying[viewportIndex];
|
||||||
Session.set('UpdateCINE', Random.id());
|
Session.set('UpdateCINE', Random.id());
|
||||||
},
|
|
||||||
previousPresentationGroup: function() {
|
|
||||||
WindowManager.previousPresentationGroup();
|
|
||||||
},
|
|
||||||
nextPresentationGroup: function() {
|
|
||||||
WindowManager.nextPresentationGroup();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,7 +97,6 @@ Template.viewer.onCreated(function() {
|
|||||||
var patientId = this.data.studies[0].patientId;
|
var patientId = this.data.studies[0].patientId;
|
||||||
Session.set('patientId', patientId);
|
Session.set('patientId', patientId);
|
||||||
|
|
||||||
initialized = false;
|
|
||||||
self.autorun(function() {
|
self.autorun(function() {
|
||||||
var patientId = Session.get('patientId');
|
var patientId = Session.get('patientId');
|
||||||
self.subscribe('timepoints', patientId);
|
self.subscribe('timepoints', patientId);
|
||||||
@ -113,38 +106,35 @@ Template.viewer.onCreated(function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initialized === true) {
|
ViewerStudies.find().observe({
|
||||||
return;
|
added: function(study) {
|
||||||
}
|
var timepoint = Timepoints.findOne({timepointName: study.studyDate});
|
||||||
|
if (timepoint) {
|
||||||
|
log.warn("A timepoint with that study date already exists!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ViewerStudies.find().forEach(function(study) {
|
var timepointID = uuid.v4();
|
||||||
var timepoint = Timepoints.findOne({timepointName: study.studyDate});
|
|
||||||
if (timepoint) {
|
var testTimepoint = Timepoints.findOne({});
|
||||||
log.warn("A timepoint with that study date already exists!");
|
if (testTimepoint && testTimepoint.patientId !== study.patientId) {
|
||||||
return;
|
log.warn("Timepoints collection related to the wrong subject");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info('Inserting a new timepoint');
|
||||||
|
Timepoints.insert({
|
||||||
|
patientId: study.patientId,
|
||||||
|
timepointID: timepointID,
|
||||||
|
timepointName: study.studyDate
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var timepointID = uuid.v4();
|
|
||||||
|
|
||||||
var testTimepoint = Timepoints.findOne({});
|
|
||||||
if (testTimepoint && testTimepoint.patientId !== study.patientId) {
|
|
||||||
log.warn("Timepoints collection related to the wrong subject");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info('Inserting a new timepoint');
|
|
||||||
Timepoints.insert({
|
|
||||||
patientId: study.patientId,
|
|
||||||
timepointID: timepointID,
|
|
||||||
timepointName: study.studyDate
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is used to re-add tools from the database into the
|
// This is used to re-add tools from the database into the
|
||||||
// Cornerstone ToolData structure
|
// Cornerstone ToolData structure
|
||||||
Measurements.find().observe({
|
Measurements.find().observe({
|
||||||
added: function (data) {
|
added: function (data) {
|
||||||
|
|
||||||
if (data.toolDataInsertedManually === true) {
|
if (data.toolDataInsertedManually === true) {
|
||||||
|
|
||||||
// Activate first measurements in image box as default if exists
|
// Activate first measurements in image box as default if exists
|
||||||
@ -156,19 +146,40 @@ Template.viewer.onCreated(function() {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('Measurement added');
|
log.info('Measurement added');
|
||||||
|
|
||||||
addMeasurementAsToolData(data);
|
addMeasurementAsToolData(data);
|
||||||
|
|
||||||
|
updateRelatedElements(data.imageId);
|
||||||
|
},
|
||||||
|
changed: function(data) {
|
||||||
|
log.info('Measurement changed');
|
||||||
|
updateRelatedElements(data.imageId);
|
||||||
|
},
|
||||||
|
removed: function(data) {
|
||||||
|
log.info('Measurement removed');
|
||||||
|
updateRelatedElements(data.imageId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer("CornerstoneNewImage", cornerstoneTools.updateImageSynchronizer);
|
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer("CornerstoneNewImage", cornerstoneTools.updateImageSynchronizer);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateRelatedElements(imageId) {
|
||||||
|
// Get all on-screen elements with this imageId
|
||||||
|
var enabledElements = cornerstone.getEnabledElementsByImageId(imageId);
|
||||||
|
|
||||||
|
// TODO=Check original event to prevent duplicate updateImage calls
|
||||||
|
|
||||||
|
// Loop through these elements
|
||||||
|
enabledElements.forEach(function(enabledElement) {
|
||||||
|
// Update the display so the tool is removed
|
||||||
|
var element = enabledElement.element;
|
||||||
|
cornerstone.updateImage(element)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function addMeasurementAsToolData(data) {
|
function addMeasurementAsToolData(data) {
|
||||||
// Check what toolType we should be adding this to, based on the isTarget value
|
// Check what toolType we should be adding this to, based on the isTarget value
|
||||||
// of the stored Measurement
|
// of the stored Measurement
|
||||||
@ -184,10 +195,41 @@ function addMeasurementAsToolData(data) {
|
|||||||
toolState[imageId] = {};
|
toolState[imageId] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is probably not the best approach to prevent duplicates
|
||||||
|
if (toolState[imageId][toolType] && toolState[imageId][toolType].data) {
|
||||||
|
var measurementHasNoIdYet = false;
|
||||||
|
toolState[imageId][toolType].data.forEach(function(measurement) {
|
||||||
|
if (measurement.id === 'notready') {
|
||||||
|
measurementHasNoIdYet = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stop here if it appears that we are creating this measurement right now,
|
||||||
|
// and would not like this function to add another copy of it to the toolData
|
||||||
|
if (measurementHasNoIdYet === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!toolState[imageId][toolType]) {
|
if (!toolState[imageId][toolType]) {
|
||||||
toolState[imageId][toolType] = {
|
toolState[imageId][toolType] = {
|
||||||
data: []
|
data: []
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
var alreadyExists = false;
|
||||||
|
if (toolState[imageId][toolType].data.length) {
|
||||||
|
toolState[imageId][toolType].data.forEach(function(measurement) {
|
||||||
|
if (measurement.id === data._id) {
|
||||||
|
alreadyExists = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alreadyExists === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create measurementData structure based on the lesion data at this timepoint
|
// Create measurementData structure based on the lesion data at this timepoint
|
||||||
@ -204,6 +246,7 @@ function addMeasurementAsToolData(data) {
|
|||||||
measurementData.visible = data.visible;
|
measurementData.visible = data.visible;
|
||||||
measurementData.active = data.active;
|
measurementData.active = data.active;
|
||||||
measurementData.uid = data.uid;
|
measurementData.uid = data.uid;
|
||||||
|
measurementData.id = data._id;
|
||||||
|
|
||||||
toolState[imageId][toolType].data.push(measurementData);
|
toolState[imageId][toolType].data.push(measurementData);
|
||||||
});
|
});
|
||||||
@ -215,6 +258,46 @@ Template.viewer.onDestroyed(function() {
|
|||||||
OHIF.viewer.updateImageSynchronizer.destroy();
|
OHIF.viewer.updateImageSynchronizer.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Template.viewer.events({
|
||||||
|
'CornerstoneToolsMeasurementModified .imageViewerViewport': function(e, template, eventData) {
|
||||||
|
handleMeasurementModified(e, eventData);
|
||||||
|
},
|
||||||
|
'CornerstoneToolsMeasurementRemoved .imageViewerViewport': function(e, template, eventData) {
|
||||||
|
handleMeasurementRemoved(e, eventData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleMeasurementModified(e, eventData) {
|
||||||
|
log.info('CornerstoneToolsMeasurementModified');
|
||||||
|
var measurementData = eventData.measurementData;
|
||||||
|
|
||||||
|
switch (eventData.toolType) {
|
||||||
|
case 'nonTarget':
|
||||||
|
case 'lesion':
|
||||||
|
measurementManagerDAL.updateTimepointData(measurementData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMeasurementRemoved(e, eventData) {
|
||||||
|
log.info('CornerstoneToolsMeasurementRemoved');
|
||||||
|
var measurementData = eventData.measurementData;
|
||||||
|
var databaseEntry;
|
||||||
|
|
||||||
|
switch (eventData.toolType) {
|
||||||
|
case 'nonTarget':
|
||||||
|
case 'lesion':
|
||||||
|
databaseEntry = Measurements.findOne(measurementData.id, {reactive: false});
|
||||||
|
if (!databaseEntry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO= Fix this when we have Findings that relate to more than one viewport
|
||||||
|
Measurements.remove(databaseEntry._id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid doing DOM manipulation during the resize handler
|
// Avoid doing DOM manipulation during the resize handler
|
||||||
// because it is fired very often.
|
// because it is fired very often.
|
||||||
// Resizing is therefore performed 100 ms after the resize event stops.
|
// Resizing is therefore performed 100 ms after the resize event stops.
|
||||||
|
|||||||
108
Packages/lesiontracker/client/collections/LesionLocations.js
Normal file
108
Packages/lesiontracker/client/collections/LesionLocations.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
LesionLocations = new Meteor.Collection(null);
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'liverLeft',
|
||||||
|
group: 'liver',
|
||||||
|
location: "Liver Left",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'liverRight',
|
||||||
|
group: 'liver',
|
||||||
|
location: "Liver Right",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'liverCaudate',
|
||||||
|
group: 'liver',
|
||||||
|
location: "Liver Caudate",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'lungLLL',
|
||||||
|
group: 'lung',
|
||||||
|
location: "Lung LLL",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'lungLUL',
|
||||||
|
group: 'lung',
|
||||||
|
location: "Lung LUL",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'lungRLL',
|
||||||
|
group: 'lung',
|
||||||
|
location: "Lung RLL",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'lungRML',
|
||||||
|
group: 'lung',
|
||||||
|
location: "Lung RML",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'lungRUL',
|
||||||
|
group: 'lung',
|
||||||
|
location: "Lung RUL",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'pleuraLeft',
|
||||||
|
group: 'pleura',
|
||||||
|
location: "Pleura Left",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'pleuraRight',
|
||||||
|
group: 'pleura',
|
||||||
|
location: "Pleura Right",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'kidneyLeft',
|
||||||
|
group: 'kidney',
|
||||||
|
location: "Kidney Left",
|
||||||
|
hasDescription: false,
|
||||||
|
description: "",
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
|
id: 'kidneyRight',
|
||||||
|
group: 'kidney',
|
||||||
|
location: "Kidney Right",
|
||||||
|
hasDescription: false,
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
LocationResponses = new Meteor.Collection(null);
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Complete response",
|
||||||
|
code: "CR",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Progressive disease",
|
||||||
|
code: "PD",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Complete response",
|
||||||
|
code: "CR",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Stable disease",
|
||||||
|
code: "SD",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Non-measurable",
|
||||||
|
code: "NM",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Unknown",
|
||||||
|
code: "UN",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Not Evaluable",
|
||||||
|
code: "NE",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Non-CR/Non-PD",
|
||||||
|
code: "NN",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
LocationResponses.insert({
|
||||||
|
text: "Excluded",
|
||||||
|
code: "EX",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
@ -71,7 +71,7 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
cornerstoneTools.removeToolState(element, toolType, measurementData);
|
cornerstoneTools.removeToolState(element, toolType, measurementData);
|
||||||
} else {
|
} else {
|
||||||
// Set lesionMeasurementData Session
|
// Set lesionMeasurementData Session
|
||||||
config.getLesionLocationCallback(measurementData, mouseEventData);
|
config.getLesionLocationCallback(measurementData, mouseEventData, doneCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(element).on('CornerstoneToolsMouseMove', eventData, cornerstoneTools.lesion.mouseMoveCallback);
|
$(element).on('CornerstoneToolsMouseMove', eventData, cornerstoneTools.lesion.mouseMoveCallback);
|
||||||
@ -157,7 +157,8 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
pointNearHandle: pointNearTextBox,
|
pointNearHandle: pointNearTextBox,
|
||||||
active: false,
|
active: false,
|
||||||
movesIndependently: true,
|
movesIndependently: true,
|
||||||
drawnIndependently: true
|
drawnIndependently: true,
|
||||||
|
allowedOutsideImage: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
imageId: imageId,
|
imageId: imageId,
|
||||||
@ -282,10 +283,7 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
// Set measurement text to show lesion table
|
// Set measurement text to show lesion table
|
||||||
data.measurementText = length.toFixed(1);
|
data.measurementText = length.toFixed(1);
|
||||||
|
|
||||||
|
|
||||||
context.restore();
|
context.restore();
|
||||||
|
|
||||||
updateLesionCollection(toolData.data[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +299,58 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////// END IMAGE RENDERING ///////
|
function doubleClickCallback(e, eventData) {
|
||||||
|
// Prevent other double click handlers from firing after this one
|
||||||
|
//e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
var element = eventData.element;
|
||||||
|
var data;
|
||||||
|
|
||||||
|
function doneCallback(data, deleteTool) {
|
||||||
|
if (deleteTool === true) {
|
||||||
|
cornerstoneTools.removeToolState(element, toolType, data);
|
||||||
|
cornerstone.updateImage(element);
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*// TODO= Find a better way to do this! This is very messy
|
||||||
|
config.setLesionNumberCallback(data, eventData, function(lesionNumber) {
|
||||||
|
data.lesionName = "Target " + lesionNumber;
|
||||||
|
data.lesionNumber = lesionNumber;
|
||||||
|
data.active = false;
|
||||||
|
cornerstone.updateImage(element);
|
||||||
|
});*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.data && e.data.mouseButtonMask && !cornerstoneTools.isMouseButtonEnabled(eventData.which, e.data.mouseButtonMask)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = cornerstoneTools.lesion.getConfiguration();
|
||||||
|
|
||||||
|
var coords = eventData.currentPoints.canvas;
|
||||||
|
var toolData = cornerstoneTools.getToolState(element, toolType);
|
||||||
|
|
||||||
|
// now check to see if there is a handle we can move
|
||||||
|
if (!toolData) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < toolData.data.length; i++) {
|
||||||
|
data = toolData.data[i];
|
||||||
|
if (pointNearTool(element, data, coords)) {
|
||||||
|
data.active = true;
|
||||||
|
cornerstone.updateImage(element);
|
||||||
|
// Allow relabelling via a callback
|
||||||
|
config.changeLesionLocationCallback(data, eventData, doneCallback);
|
||||||
|
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // false = causes jquery to preventDefault() and stopPropagation() this event
|
||||||
|
}
|
||||||
|
|
||||||
// module exports
|
// module exports
|
||||||
cornerstoneTools.lesion = cornerstoneTools.mouseButtonTool({
|
cornerstoneTools.lesion = cornerstoneTools.mouseButtonTool({
|
||||||
@ -309,6 +358,7 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
addNewMeasurement: addNewMeasurement,
|
addNewMeasurement: addNewMeasurement,
|
||||||
onImageRendered: onImageRendered,
|
onImageRendered: onImageRendered,
|
||||||
pointNearTool: pointNearTool,
|
pointNearTool: pointNearTool,
|
||||||
|
mouseDoubleClickCallback: doubleClickCallback,
|
||||||
toolType: toolType
|
toolType: toolType
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,12 +46,9 @@ var measurementManagerDAL = (function() {
|
|||||||
lesionDataObject.timepoints = timepointsObject;
|
lesionDataObject.timepoints = timepointsObject;
|
||||||
|
|
||||||
// Is there a use for this?
|
// Is there a use for this?
|
||||||
lesionDataObject.number = Measurements.find().count() + 1;
|
lesionDataObject.number = Measurements.find().count() + 1;
|
||||||
|
|
||||||
// TODO=Fix this workaround to prevent the observe hook from adding another set of toolData
|
lesionDataObject.id = Measurements.insert(lesionDataObject);
|
||||||
lesionDataObject.toolDataInsertedManually = true;
|
|
||||||
|
|
||||||
Measurements.insert(lesionDataObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update timepoint data in Measurements collection
|
// Update timepoint data in Measurements collection
|
||||||
@ -82,6 +79,7 @@ var measurementManagerDAL = (function() {
|
|||||||
timepoints[timepointID].studyInstanceUid = lesionData.studyInstanceUid;
|
timepoints[timepointID].studyInstanceUid = lesionData.studyInstanceUid;
|
||||||
timepoints[timepointID].handles = lesionData.handles;
|
timepoints[timepointID].handles = lesionData.handles;
|
||||||
|
|
||||||
|
lesionData.id = measurement._id;
|
||||||
|
|
||||||
Measurements.update(measurement._id, {
|
Measurements.update(measurement._id, {
|
||||||
$set: {
|
$set: {
|
||||||
@ -133,7 +131,7 @@ var measurementManagerDAL = (function() {
|
|||||||
|
|
||||||
if (!timepoints[timepointID]) {
|
if (!timepoints[timepointID]) {
|
||||||
// Find lesion number for this timepointID
|
// Find lesion number for this timepointID
|
||||||
return measurement.lesionNumber
|
return measurement.lesionNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timepoints[timepointID].longestDiameter === '') {
|
if (timepoints[timepointID].longestDiameter === '') {
|
||||||
@ -118,7 +118,8 @@
|
|||||||
pointNearHandle: pointNearTextBox,
|
pointNearHandle: pointNearTextBox,
|
||||||
active: false,
|
active: false,
|
||||||
movesIndependently: true,
|
movesIndependently: true,
|
||||||
drawnIndependently: true
|
drawnIndependently: true,
|
||||||
|
allowedOutsideImage: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
imageId: imageId,
|
imageId: imageId,
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
<template name="lesionLocationDialog">
|
||||||
|
<div id="lesionLocationDialog">
|
||||||
|
<div class="dialogHeader">
|
||||||
|
<h4>Select Lesion Location</h4>
|
||||||
|
</div>
|
||||||
|
<div class="dialogContent">
|
||||||
|
<div class="lesionLocation">
|
||||||
|
<label>Lesion Location</label>
|
||||||
|
<select class="selectLesionLocation">
|
||||||
|
<option value="-1"></option>
|
||||||
|
{{ #each lesionLocations}}
|
||||||
|
<option value='{{_id}}'>{{location}}</option>
|
||||||
|
{{ /each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="lesionLocationRelabelDialog">
|
||||||
|
<div class="dialogHeader">
|
||||||
|
<h4>Change Lesion Location</h4>
|
||||||
|
</div>
|
||||||
|
<a></a>
|
||||||
|
<div class="dialogContent">
|
||||||
|
<div class="lesionLocation">
|
||||||
|
<label>Lesion Location</label>
|
||||||
|
<select class="selectLesionLocation">
|
||||||
|
<option value="-1"></option>
|
||||||
|
{{ #each lesionLocations}}
|
||||||
|
<option value='{{_id}}' selected={{selected}}>{{location}}</option>
|
||||||
|
{{ /each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button id="removeLesion" class="btn btn-link">Remove</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,247 @@
|
|||||||
|
function closeHandler(dialog) {
|
||||||
|
// Hide the lesion dialog
|
||||||
|
$(dialog).css('display', 'none');
|
||||||
|
|
||||||
|
// Remove the backdrop
|
||||||
|
$(".removableBackdrop").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This event sets lesion number for new lesion
|
||||||
|
function setLesionNumberCallback(measurementData, eventData, doneCallback) {
|
||||||
|
// Get the current element's timepointID from the study date metadata
|
||||||
|
var element = eventData.element;
|
||||||
|
var enabledElement = cornerstone.getEnabledElement(element);
|
||||||
|
var imageId = enabledElement.image.imageId;
|
||||||
|
|
||||||
|
var study = cornerstoneTools.metaData.get('study', imageId);
|
||||||
|
var timepoint = Timepoints.findOne({timepointName: study.studyDate});
|
||||||
|
if (!timepoint) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
measurementData.timepointID = timepoint.timepointID;
|
||||||
|
|
||||||
|
// Get a lesion number for this lesion, depending on whether or not the same lesion previously
|
||||||
|
// exists at a different timepoint
|
||||||
|
var lesionNumber = measurementManagerDAL.getNewLesionNumber(measurementData.timepointID, isTarget=true);
|
||||||
|
measurementData.lesionNumber = lesionNumber;
|
||||||
|
|
||||||
|
// Set lesion number
|
||||||
|
doneCallback(lesionNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This event determines whether or not to show the lesion dialog
|
||||||
|
// If there already exists a lesion with this specific lesion number,
|
||||||
|
// related to the chosen location.
|
||||||
|
function getLesionLocationCallback(measurementData, eventData) {
|
||||||
|
Template.lesionLocationDialog.measurementData = measurementData;
|
||||||
|
|
||||||
|
// Reset the doneCallback saved in the template so we don't call the change event's done callback
|
||||||
|
Template.lesionLocationDialog.doneCallback = undefined;
|
||||||
|
|
||||||
|
// Get the lesion location dialog
|
||||||
|
var dialog = $("#lesionLocationDialog");
|
||||||
|
Template.lesionLocationDialog.dialog = dialog;
|
||||||
|
|
||||||
|
// Show the backdrop
|
||||||
|
UI.render(Template.removableBackdrop, document.body);
|
||||||
|
|
||||||
|
// Make sure the context menu is closed when the user clicks away
|
||||||
|
$(".removableBackdrop").one('mousedown touchstart', function() {
|
||||||
|
closeHandler(dialog);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Select the first option for now
|
||||||
|
var selector = dialog.find("select.selectLesionLocation");
|
||||||
|
selector.find("option:first").prop("selected", true);
|
||||||
|
|
||||||
|
// Find out if this lesion number is already added in the lesion manager for another timepoint
|
||||||
|
// If it is, stop here because we don't need the dialog.
|
||||||
|
var locationUID = measurementManagerDAL.lesionNumberExists(measurementData);
|
||||||
|
if (locationUID) {
|
||||||
|
// Add an ID value to the tool data to link it to the Measurements collection
|
||||||
|
measurementData.id = 'notready';
|
||||||
|
|
||||||
|
measurementData.locationUID = locationUID;
|
||||||
|
measurementManagerDAL.updateTimepointData(measurementData);
|
||||||
|
closeHandler();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If it isn't, continue to open the dialog and have the user choose a lesion location
|
||||||
|
|
||||||
|
// Show the lesion location dialog above
|
||||||
|
var dialogProperty = {
|
||||||
|
top: eventData.currentPoints.page.y - dialog.outerHeight() - 40,
|
||||||
|
left: eventData.currentPoints.page.x - dialog.outerWidth() / 2,
|
||||||
|
display: 'block'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Device is touch device or not
|
||||||
|
// If device is touch device, set position center of screen vertically and horizontally
|
||||||
|
if (isTouchDevice()) {
|
||||||
|
// add dialogMobile class to provide a black,transparent background
|
||||||
|
dialog.addClass("dialogMobile");
|
||||||
|
dialogProperty.top = 0;
|
||||||
|
dialogProperty.left = 0;
|
||||||
|
dialogProperty.right = 0;
|
||||||
|
dialogProperty.bottom = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.css(dialogProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeLesionLocationCallback(measurementData, eventData, doneCallback) {
|
||||||
|
Template.lesionLocationDialog.measurementData = measurementData;
|
||||||
|
Template.lesionLocationDialog.doneCallback = doneCallback;
|
||||||
|
|
||||||
|
// Get the lesion location dialog
|
||||||
|
var dialog = $("#lesionLocationRelabelDialog");
|
||||||
|
Template.lesionLocationDialog.dialog = dialog;
|
||||||
|
|
||||||
|
// Show the backdrop
|
||||||
|
UI.render(Template.removableBackdrop, document.body);
|
||||||
|
|
||||||
|
// Make sure the context menu is closed when the user clicks away
|
||||||
|
$(".removableBackdrop").one('mousedown touchstart', function() {
|
||||||
|
closeHandler(dialog);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show the lesion location dialog above
|
||||||
|
var dialogProperty = {
|
||||||
|
top: eventData.currentPoints.page.y - dialog.outerHeight() - 40,
|
||||||
|
left: eventData.currentPoints.page.x - dialog.outerWidth() / 2,
|
||||||
|
display: 'block'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Device is touch device or not
|
||||||
|
// If device is touch device, set position center of screen vertically and horizontally
|
||||||
|
if (isTouchDevice()) {
|
||||||
|
// add dialogMobile class to provide a black,transparent background
|
||||||
|
dialog.addClass("dialogMobile");
|
||||||
|
dialogProperty.top = 0;
|
||||||
|
dialogProperty.left = 0;
|
||||||
|
dialogProperty.right = 0;
|
||||||
|
dialogProperty.bottom = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.css(dialogProperty);
|
||||||
|
|
||||||
|
var measurement = Measurements.findOne(measurementData.id);
|
||||||
|
if (!measurement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentLocation = LesionLocations.findOne({
|
||||||
|
id: measurement.locationId
|
||||||
|
});
|
||||||
|
|
||||||
|
LesionLocations.update({},
|
||||||
|
{$set: {selected: false}},
|
||||||
|
{ multi: true });
|
||||||
|
|
||||||
|
LesionLocations.update(currentLocation._id, {
|
||||||
|
$set: {
|
||||||
|
selected: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
setLesionNumberCallback: setLesionNumberCallback,
|
||||||
|
getLesionLocationCallback: getLesionLocationCallback,
|
||||||
|
changeLesionLocationCallback: changeLesionLocationCallback
|
||||||
|
};
|
||||||
|
|
||||||
|
cornerstoneTools.lesion.setConfiguration(config);
|
||||||
|
|
||||||
|
Template.lesionLocationDialog.events({
|
||||||
|
'change .selectLesionLocation': function(e) {
|
||||||
|
var measurementData = Template.lesionLocationDialog.measurementData;
|
||||||
|
var doneCallback = Template.lesionLocationDialog.doneCallback;
|
||||||
|
var dialog = Template.lesionLocationDialog.dialog;
|
||||||
|
|
||||||
|
// Get the current value of the selector
|
||||||
|
var selectedOptionId = e.currentTarget.value;
|
||||||
|
|
||||||
|
// If the selected option is still the default (-1)
|
||||||
|
// then stop here
|
||||||
|
if (selectedOptionId < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get selected location data
|
||||||
|
var locationObj = LesionLocations.findOne({_id: selectedOptionId});
|
||||||
|
|
||||||
|
var id;
|
||||||
|
var existingLocation = PatientLocations.findOne({location: locationObj.location});
|
||||||
|
if (existingLocation) {
|
||||||
|
id = existingLocation._id;
|
||||||
|
} else {
|
||||||
|
// Adds location data to PatientLocation and retrieve the location ID
|
||||||
|
id = PatientLocations.insert({
|
||||||
|
location: locationObj.location,
|
||||||
|
locationId: locationObj._id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an ID value to the tool data to link it to the Measurements collection
|
||||||
|
if (!measurementData.id) {
|
||||||
|
measurementData.id = 'notready';
|
||||||
|
|
||||||
|
// Link locationUID with active lesion measurementData
|
||||||
|
measurementData.locationId = locationObj.id;
|
||||||
|
measurementData.locationUID = id;
|
||||||
|
|
||||||
|
/// Set the isTarget value to true, since this is the target-lesion dialog callback
|
||||||
|
measurementData.isTarget = true;
|
||||||
|
|
||||||
|
// Adds lesion data to timepoints array
|
||||||
|
measurementManagerDAL.addLesionData(measurementData);
|
||||||
|
} else {
|
||||||
|
Measurements.update(measurementData.id, {
|
||||||
|
$set: {
|
||||||
|
location: locationObj.location,
|
||||||
|
locationId: locationObj.id,
|
||||||
|
locationUID: id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the dialog
|
||||||
|
closeHandler(dialog);
|
||||||
|
|
||||||
|
if (doneCallback && typeof doneCallback === 'function') {
|
||||||
|
doneCallback(measurementData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click #removeLesion': function() {
|
||||||
|
var measurementData = Template.lesionLocationDialog.measurementData;
|
||||||
|
var doneCallback = Template.lesionLocationDialog.doneCallback;
|
||||||
|
var dialog = Template.lesionLocationDialog.dialog;
|
||||||
|
|
||||||
|
if (doneCallback && typeof doneCallback === 'function') {
|
||||||
|
var deleteTool = true;
|
||||||
|
doneCallback(measurementData, deleteTool);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeHandler(dialog);
|
||||||
|
},
|
||||||
|
'click #btnCloseLesionPopup': function() {
|
||||||
|
var dialog = Template.lesionLocationDialog.dialog;
|
||||||
|
closeHandler(dialog);
|
||||||
|
},
|
||||||
|
'keypress #lesionLocationDialog, keypress #lesionLocationRelabelDialog': function(e) {
|
||||||
|
var dialog = Template.lesionLocationDialog.dialog;
|
||||||
|
|
||||||
|
// If Enter is pressed, close the dialog
|
||||||
|
if (e.which === 13) {
|
||||||
|
closeHandler(dialog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.lesionLocationDialog.helpers({
|
||||||
|
'lesionLocations': function() {
|
||||||
|
return LesionLocations.find();
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
#lesionLocationDialog, #lesionLocationRelabelDialog
|
||||||
|
display: none
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
bottom: 0
|
||||||
|
left: 0
|
||||||
|
right: 0
|
||||||
|
z-index: 100
|
||||||
|
width: 300px
|
||||||
|
border-radius: 5px
|
||||||
|
padding: 10px 20px 10px 20px
|
||||||
|
background-color: rgba(255,255,255,1)
|
||||||
|
|
||||||
|
/* dialogMobile is added to #lesionLocationDialog when touchDevices is detected */
|
||||||
|
.dialogMobile
|
||||||
|
margin: 0 auto
|
||||||
|
float: none
|
||||||
|
background-color: rgba(0,0,0,0.5)
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
#closeLesionPopup
|
||||||
|
outline: none
|
||||||
|
border: none
|
||||||
|
background-color: transparent
|
||||||
|
|
||||||
|
#selectLesionLocation
|
||||||
|
margin-top: 5px
|
||||||
|
|
||||||
|
.dialogContent
|
||||||
|
margin-bottom: 10px
|
||||||
|
|
||||||
|
#removeLesion
|
||||||
|
outline: none
|
||||||
|
text-decoration: none
|
||||||
|
|
||||||
|
#lesionLocationDialog
|
||||||
|
height: 110px
|
||||||
|
|
||||||
|
#lesionLocationRelabelDialog
|
||||||
|
height: 125px
|
||||||
@ -41,6 +41,11 @@ activateLesion = function(measurementId, templateData) {
|
|||||||
$(".imageViewerViewport").each(function(viewportIndex, element) {
|
$(".imageViewerViewport").each(function(viewportIndex, element) {
|
||||||
// Stop if we run out of timepoints before viewports
|
// Stop if we run out of timepoints before viewports
|
||||||
if (viewportIndex >= timepointsWithEntries.length) {
|
if (viewportIndex >= timepointsWithEntries.length) {
|
||||||
|
// Update the element anyway, to remove any other highlights that are present
|
||||||
|
deactivateAllToolData(element, 'lesion');
|
||||||
|
deactivateAllToolData(element, 'nonTarget');
|
||||||
|
cornerstone.updateImage(element);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +62,10 @@ activateLesion = function(measurementId, templateData) {
|
|||||||
|
|
||||||
// If there is no measurement data to display, stop here
|
// If there is no measurement data to display, stop here
|
||||||
if (!measurementAtTimepoint) {
|
if (!measurementAtTimepoint) {
|
||||||
|
// Update the element anyway, to remove any other highlights that are present
|
||||||
|
deactivateAllToolData(element, 'lesion');
|
||||||
|
deactivateAllToolData(element, 'nonTarget');
|
||||||
|
cornerstone.updateImage(element);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +256,6 @@ Template.lesionTable.events({
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.lesionTable.onCreated(function(){
|
Template.lesionTable.onCreated(function(){
|
||||||
@ -275,14 +283,13 @@ Tracker.autorun(function () {
|
|||||||
dates: []
|
dates: []
|
||||||
};
|
};
|
||||||
|
|
||||||
$("#"+contentId+" .imageViewerViewport").each(function(viewportIndex, element) {
|
$(".imageViewerViewport").each(function(viewportIndex, element) {
|
||||||
var enabledElement = cornerstone.getEnabledElement(element);
|
var enabledElement = cornerstone.getEnabledElement(element);
|
||||||
if(enabledElement && enabledElement.image){
|
if(enabledElement && enabledElement.image){
|
||||||
var imageId = enabledElement.image.imageId;
|
var imageId = enabledElement.image.imageId;
|
||||||
var study = cornerstoneTools.metaData.get('study', imageId);
|
var study = cornerstoneTools.metaData.get('study', imageId);
|
||||||
var studyDate = study.studyDate;
|
var studyDate = study.studyDate;
|
||||||
var patientId = study.patientId;
|
loadedStudyDates.patientId = study.patientId;
|
||||||
loadedStudyDates.patientId = patientId;
|
|
||||||
// Check studyDate is added before
|
// Check studyDate is added before
|
||||||
if (loadedStudyDates.dates.indexOf(studyDate) < 0) {
|
if (loadedStudyDates.dates.indexOf(studyDate) < 0) {
|
||||||
loadedStudyDates.dates.push(studyDate);
|
loadedStudyDates.dates.push(studyDate);
|
||||||
@ -306,7 +313,6 @@ Tracker.autorun(function () {
|
|||||||
$set: {
|
$set: {
|
||||||
timepointLoaded: timepointLoaded
|
timepointLoaded: timepointLoaded
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<template name="nonTargetLesionDialog">
|
||||||
|
<div id="nonTargetLesionLocationDialog">
|
||||||
|
<div class="dialogHeader">
|
||||||
|
<div class="dialogHeader">
|
||||||
|
<div><h4>Select Lesion Location</h4></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialogContent">
|
||||||
|
<div class="lesionLocation">
|
||||||
|
<div class="elementContainer">
|
||||||
|
<label>Lesion Location</label>
|
||||||
|
</div>
|
||||||
|
<div class="elementContainer">
|
||||||
|
<select id="selectNonTargetLesionLocation">
|
||||||
|
<option value="-1"></option>
|
||||||
|
{{ #each lesionLocations}}
|
||||||
|
<option value='{{_id}}'>{{location}}</option>
|
||||||
|
{{ /each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="locationResponse">
|
||||||
|
<div class="elementContainer">
|
||||||
|
<label>Response</label>
|
||||||
|
</div>
|
||||||
|
<div class="elementContainer">
|
||||||
|
<select id="selectNonTargetLesionLocationResponse">
|
||||||
|
<option value="-1"></option>
|
||||||
|
{{ #each locationResponses}}
|
||||||
|
<option value='{{code}}'>{{code}} - {{text}}</option>
|
||||||
|
{{ /each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="locationOK">
|
||||||
|
<button class="btn btn-primary" id="nonTargetLesionOK">OK</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -1,5 +1,12 @@
|
|||||||
// This event sets lesion number for new lesion
|
function closeHandler(dialog) {
|
||||||
|
// Hide the lesion dialog
|
||||||
|
$(dialog).css('display', 'none');
|
||||||
|
|
||||||
|
// Remove the backdrop
|
||||||
|
$(".removableBackdrop").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This event sets lesion number for new lesion
|
||||||
function setLesionNumberCallback(measurementData, eventData, doneCallback) {
|
function setLesionNumberCallback(measurementData, eventData, doneCallback) {
|
||||||
// Get the current element's timepointID from the study date metadata
|
// Get the current element's timepointID from the study date metadata
|
||||||
var element = eventData.element;
|
var element = eventData.element;
|
||||||
@ -29,27 +36,43 @@ function setLesionNumberCallback(measurementData, eventData, doneCallback) {
|
|||||||
// This event determines whether or not to show the Non-Target lesion dialog
|
// This event determines whether or not to show the Non-Target lesion dialog
|
||||||
// If there already exists a lesion with this specific lesion number,
|
// If there already exists a lesion with this specific lesion number,
|
||||||
// related to the chosen location.
|
// related to the chosen location.
|
||||||
|
|
||||||
function getNonTargetLesionLocationCallback(measurementData, eventData) {
|
function getNonTargetLesionLocationCallback(measurementData, eventData) {
|
||||||
|
Template.nonTargetLesionDialog.measurementData = measurementData;
|
||||||
|
|
||||||
// Get the non-target lesion location dialog
|
// Get the non-target lesion location dialog
|
||||||
var nonTargetlesionDialog = $("#nonTargetLesionLocationDialog");
|
var dialog = $("#nonTargetLesionLocationDialog");
|
||||||
|
Template.nonTargetLesionDialog.dialog = dialog;
|
||||||
|
|
||||||
|
// Show the backdrop
|
||||||
|
UI.render(Template.removableBackdrop, document.body);
|
||||||
|
|
||||||
|
// Make sure the context menu is closed when the user clicks away
|
||||||
|
$(".removableBackdrop").one('mousedown touchstart', function() {
|
||||||
|
closeHandler(dialog);
|
||||||
|
|
||||||
|
if (doneCallback && typeof doneCallback === 'function') {
|
||||||
|
var deleteTool = true;
|
||||||
|
doneCallback(measurementData, deleteTool);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Find the select option box
|
// Find the select option box
|
||||||
var selectorLocation = nonTargetlesionDialog.find("select#selectNonTargetLesionLocation");
|
var selectorLocation = dialog.find("select#selectNonTargetLesionLocation");
|
||||||
var selectorResponse = nonTargetlesionDialog.find("select#selectNonTargetLesionLocationResponse");
|
var selectorResponse = dialog.find("select#selectNonTargetLesionLocationResponse");
|
||||||
|
|
||||||
// OK button
|
selectorLocation.find("option:first").prop("selected", "selected");
|
||||||
var btnOK = nonTargetlesionDialog.find("button#nonTargetLesionOK");
|
selectorResponse.find("option:first").prop("selected", "selected");
|
||||||
|
|
||||||
|
// Allow location selection
|
||||||
// If selector location is disabled, make it enable
|
selectorLocation.removeAttr("disabled");
|
||||||
enableLocationSelection();
|
|
||||||
|
|
||||||
// Find out if this lesion number is already added in the lesion manager for another timepoint
|
// Find out if this lesion number is already added in the lesion manager for another timepoint
|
||||||
// If it is, disable selector location
|
// If it is, disable selector location
|
||||||
var locationUID = measurementManagerDAL.lesionNumberExists(measurementData);
|
var locationUID = measurementManagerDAL.lesionNumberExists(measurementData);
|
||||||
if (locationUID) {
|
if (locationUID) {
|
||||||
|
// Add an ID value to the tool data to link it to the Measurements collection
|
||||||
|
measurementData.id = 'notready';
|
||||||
|
|
||||||
measurementData.locationUID = locationUID;
|
measurementData.locationUID = locationUID;
|
||||||
// Disable the selection of a new location
|
// Disable the selection of a new location
|
||||||
disableLocationSelection(measurementData.locationUID);
|
disableLocationSelection(measurementData.locationUID);
|
||||||
@ -58,48 +81,16 @@ function getNonTargetLesionLocationCallback(measurementData, eventData) {
|
|||||||
// Disable selector location to prevent selecting a new location
|
// Disable selector location to prevent selecting a new location
|
||||||
function disableLocationSelection(locationUID) {
|
function disableLocationSelection(locationUID) {
|
||||||
var locationName = measurementManagerDAL.getLocationName(locationUID);
|
var locationName = measurementManagerDAL.getLocationName(locationUID);
|
||||||
selectorLocation.find('option').each(function()
|
selectorLocation.find('option').each(function() {
|
||||||
{
|
|
||||||
if ($(this).text() === locationName) {
|
if ($(this).text() === locationName) {
|
||||||
// Select location in locations dropdown list
|
// Select location in locations dropdown list
|
||||||
selectorLocation.find('option').eq($(this).index()).prop("selected", true);
|
selectorLocation.find('option').eq($(this).index()).prop("selected", true);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
selectorLocation.prop("disabled", true);
|
selectorLocation.prop("disabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable selector location
|
|
||||||
function enableLocationSelection() {
|
|
||||||
selectorLocation.removeAttr("disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeHandler() {
|
|
||||||
|
|
||||||
// Hide the lesion dialog
|
|
||||||
nonTargetlesionDialog.css('display', 'none');
|
|
||||||
// Enable selector location
|
|
||||||
enableLocationSelection();
|
|
||||||
|
|
||||||
// Get the current value of the select option box
|
|
||||||
selectorLocation.find("option:first").prop("selected", "selected");
|
|
||||||
selectorResponse.find("option:first").prop("selected", "selected");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach keypress handlers so the user can close with the Enter button
|
|
||||||
nonTargetlesionDialog.off("keypress");
|
|
||||||
nonTargetlesionDialog.on('keypress', keyPressHandler);
|
|
||||||
|
|
||||||
// This is the keypress callback function
|
|
||||||
function keyPressHandler(e) {
|
|
||||||
// If Enter is pressed, close the dialog
|
|
||||||
if (e.which === 13) {
|
|
||||||
closeHandler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the nonTargetLesion dialog above
|
// Show the nonTargetLesion dialog above
|
||||||
var dialogProperty = {
|
var dialogProperty = {
|
||||||
top: eventData.currentPoints.page.y,
|
top: eventData.currentPoints.page.y,
|
||||||
@ -111,27 +102,40 @@ function getNonTargetLesionLocationCallback(measurementData, eventData) {
|
|||||||
// If device is touch device, set position center of screen vertically and horizontally
|
// If device is touch device, set position center of screen vertically and horizontally
|
||||||
if (isTouchDevice()) {
|
if (isTouchDevice()) {
|
||||||
// add dialogMobile class to provide a black,transparent background
|
// add dialogMobile class to provide a black,transparent background
|
||||||
$(nonTargetlesionDialog).addClass("dialogMobile");
|
dialog.addClass("dialogMobile");
|
||||||
dialogProperty.top = 0;
|
dialogProperty.top = 0;
|
||||||
dialogProperty.left = 0;
|
dialogProperty.left = 0;
|
||||||
dialogProperty.right = 0;
|
dialogProperty.right = 0;
|
||||||
dialogProperty.bottom = 0;
|
dialogProperty.bottom = 0;
|
||||||
$(".contentWrapper").css({
|
|
||||||
left: ($(window).width() - $(".contentWrapper").width()) / 2,
|
|
||||||
top: ($(window).height() - $(".contentWrapper").height()) / 2
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nonTargetlesionDialog.css(dialogProperty);
|
dialog.css(dialogProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeNonTargetLesionLocationCallback(measurementData, eventData, doneCallback) {
|
||||||
|
doneCallback(prompt('Change your lesion location:'));
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
setLesionNumberCallback: setLesionNumberCallback,
|
||||||
|
getNonTargetLesionLocationCallback: getNonTargetLesionLocationCallback,
|
||||||
|
changeNonTargetLesionLocationCallback: changeNonTargetLesionLocationCallback
|
||||||
|
};
|
||||||
|
|
||||||
|
cornerstoneTools.nonTarget.setConfiguration(config);
|
||||||
|
|
||||||
|
Template.nonTargetLesionDialog.events({
|
||||||
|
'click #nonTargetLesionOK': function() {
|
||||||
|
var dialog = Template.nonTargetLesionDialog.dialog;
|
||||||
|
var measurementData = Template.nonTargetLesionDialog.measurementData;
|
||||||
|
|
||||||
|
// Find the select option box
|
||||||
|
var selectorLocation = dialog.find("select#selectNonTargetLesionLocation");
|
||||||
|
var selectorResponse = dialog.find("select#selectNonTargetLesionLocationResponse");
|
||||||
|
|
||||||
// Click OK button
|
|
||||||
// Add lesion to lesion table
|
|
||||||
btnOK.off('click');
|
|
||||||
btnOK.on('click', function(e) {
|
|
||||||
// Get the current value of the selector
|
// Get the current value of the selector
|
||||||
var selectedOptionId = selectorLocation.find("option:selected").val();
|
var selectedOptionId = selectorLocation.find("option:selected").val();
|
||||||
var responseOptionCode = nonTargetlesionDialog.find("select#selectNonTargetLesionLocationResponse option:selected").val();
|
var responseOptionId = selectorResponse.find("option:selected").val();
|
||||||
|
|
||||||
// If the selected option is still the default (-1)
|
// If the selected option is still the default (-1)
|
||||||
// then stop here
|
// then stop here
|
||||||
@ -141,7 +145,7 @@ function getNonTargetLesionLocationCallback(measurementData, eventData) {
|
|||||||
|
|
||||||
// If the selected response option is still the default (-1)
|
// If the selected response option is still the default (-1)
|
||||||
// then stop here
|
// then stop here
|
||||||
if (responseOptionCode < 0) {
|
if (responseOptionId < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,102 +161,61 @@ function getNonTargetLesionLocationCallback(measurementData, eventData) {
|
|||||||
id = PatientLocations.insert({location: locationObj.location});
|
id = PatientLocations.insert({location: locationObj.location});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link locationUID with active lesion measurementData
|
if (!measurementData.id) {
|
||||||
measurementData.locationUID = id;
|
// Add an ID value to the tool data to link it to the Measurements collection
|
||||||
|
measurementData.id = 'notready';
|
||||||
|
|
||||||
/// Set the isTarget value to true, since this is the target-lesion dialog callback
|
// Link locationUID with active lesion measurementData
|
||||||
measurementData.isTarget = false;
|
measurementData.locationUID = id;
|
||||||
|
|
||||||
// measurementText is set from location response list
|
/// Set the isTarget value to true, since this is the target-lesion dialog callback
|
||||||
measurementData.measurementText = responseOptionCode;
|
measurementData.isTarget = false;
|
||||||
|
|
||||||
// Adds lesion data to timepoints array
|
// measurementText is set from location response list
|
||||||
measurementManagerDAL.addLesionData(measurementData);
|
measurementData.measurementText = responseOptionId;
|
||||||
|
|
||||||
|
// Adds lesion data to timepoints array
|
||||||
|
measurementManagerDAL.addLesionData(measurementData);
|
||||||
|
} else {
|
||||||
|
Measurements.update(measurementData.id, {
|
||||||
|
$set: {
|
||||||
|
location: locationObj.location,
|
||||||
|
locationId: locationObj.id,
|
||||||
|
locationUID: id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Close the dialog
|
// Close the dialog
|
||||||
closeHandler();
|
closeHandler(dialog);
|
||||||
});
|
},
|
||||||
}
|
'click #removeLesion': function() {
|
||||||
|
var measurementData = Template.nonTargetLesionDialog.measurementData;
|
||||||
|
var doneCallback = Template.nonTargetLesionDialog.doneCallback;
|
||||||
|
var dialog = Template.nonTargetLesionDialog.dialog;
|
||||||
|
|
||||||
function changeNonTargetLesionLocationCallback(measurementData, eventData, doneCallback) {
|
if (doneCallback && typeof doneCallback === 'function') {
|
||||||
doneCallback(prompt('Change your lesion location:'));
|
var deleteTool = true;
|
||||||
}
|
doneCallback(measurementData, deleteTool);
|
||||||
|
}
|
||||||
|
|
||||||
var config = {
|
closeHandler(dialog);
|
||||||
setLesionNumberCallback: setLesionNumberCallback,
|
},
|
||||||
getNonTargetLesionLocationCallback: getNonTargetLesionLocationCallback,
|
'click #btnCloseLesionPopup': function() {
|
||||||
changeNonTargetLesionLocationCallback: changeNonTargetLesionLocationCallback
|
var dialog = Template.nonTargetLesionDialog.dialog;
|
||||||
};
|
closeHandler(dialog);
|
||||||
|
},
|
||||||
|
'keypress #lesionLocationDialog, keypress #lesionLocationRelabelDialog': function(e) {
|
||||||
|
var dialog = Template.nonTargetLesionDialog.dialog;
|
||||||
|
|
||||||
cornerstoneTools.nonTarget.setConfiguration(config);
|
// If Enter is pressed, close the dialog
|
||||||
|
if (e.which === 13) {
|
||||||
|
closeHandler(dialog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
LocationResponses = new Meteor.Collection(null);
|
|
||||||
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Complete response",
|
|
||||||
code: "CR",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Progressive disease",
|
|
||||||
code: "PD",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Complete response",
|
|
||||||
code: "CR",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Stable disease",
|
|
||||||
code: "SD",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Non-measurable",
|
|
||||||
code: "NM",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Unknown",
|
|
||||||
code: "UN",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Not Evaluable",
|
|
||||||
code: "NE",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Non-CR/Non-PD",
|
|
||||||
code: "NN",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
LocationResponses.insert(
|
|
||||||
{
|
|
||||||
text: "Excluded",
|
|
||||||
code: "EX",
|
|
||||||
description: ""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Template.nonTargetLesionDialog.helpers({
|
Template.nonTargetLesionDialog.helpers({
|
||||||
'lesionLocations': function() {
|
'lesionLocations': function() {
|
||||||
return LesionLocations.find();
|
return LesionLocations.find();
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
#nonTargetLesionLocationDialog
|
||||||
|
display: none
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
bottom: 0
|
||||||
|
left: 0
|
||||||
|
right: 0
|
||||||
|
z-index: 100
|
||||||
|
width: 300px
|
||||||
|
height: 230px
|
||||||
|
border-radius: 5px
|
||||||
|
padding: 10px 20px 10px 20px
|
||||||
|
background-color: rgba(255,255,255,1)
|
||||||
|
|
||||||
|
/* dialogMobile is added to #nonTargetLesionLocationDialog when touchDevices is detected */
|
||||||
|
.dialogMobile
|
||||||
|
margin: 0 auto
|
||||||
|
float: none
|
||||||
|
background-color: rgba(0,0,0,0.5)
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
#selectNonTargetLesionLocation, #selectNonTargetLesionLocationResponse
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
.dialogContent, .lesionLocation, .locationResponse
|
||||||
|
margin-bottom: 20px
|
||||||
|
|
||||||
|
.elementContainer
|
||||||
|
width: 100%
|
||||||
|
margin: 0 auto
|
||||||
|
float: none
|
||||||
|
|
||||||
|
.locationOK
|
||||||
|
text-align: center
|
||||||
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
<template name="lesionLocationDialog">
|
|
||||||
<div id="lesionLocationDialog">
|
|
||||||
<div class="lesionContentWrapper">
|
|
||||||
<div class="dialogHeader">
|
|
||||||
<h4>Select Lesion Location</h4>
|
|
||||||
</div>
|
|
||||||
<div class="dialogContent">
|
|
||||||
<div class="lesionLocation">
|
|
||||||
<label>Lesion Location</label>
|
|
||||||
<select id="selectLesionLocation">
|
|
||||||
<option value="-1"></option>
|
|
||||||
{{ #each lesionLocations}}
|
|
||||||
<option value='{{_id}}'>{{location}}</option>
|
|
||||||
{{ /each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@ -1,226 +0,0 @@
|
|||||||
// This event sets lesion number for new lesion
|
|
||||||
|
|
||||||
function setLesionNumberCallback(measurementData, eventData, doneCallback) {
|
|
||||||
// Get the current element's timepointID from the study date metadata
|
|
||||||
var element = eventData.element;
|
|
||||||
var enabledElement = cornerstone.getEnabledElement(element);
|
|
||||||
var imageId = enabledElement.image.imageId;
|
|
||||||
|
|
||||||
var study = cornerstoneTools.metaData.get('study', imageId);
|
|
||||||
var timepoint = Timepoints.findOne({timepointName: study.studyDate});
|
|
||||||
if (!timepoint) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
measurementData.timepointID = timepoint.timepointID;
|
|
||||||
|
|
||||||
// Get a lesion number for this lesion, depending on whether or not the same lesion previously
|
|
||||||
// exists at a different timepoint
|
|
||||||
var lesionNumber = measurementManagerDAL.getNewLesionNumber(measurementData.timepointID, isTarget=true);
|
|
||||||
measurementData.lesionNumber = lesionNumber;
|
|
||||||
|
|
||||||
// Set lesion number
|
|
||||||
doneCallback(lesionNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This event determines whether or not to show the lesion dialog
|
|
||||||
// If there already exists a lesion with this specific lesion number,
|
|
||||||
// related to the chosen location.
|
|
||||||
function getLesionLocationCallback(measurementData, eventData) {
|
|
||||||
// Get the lesion location dialog
|
|
||||||
var lesionDialog = $("#lesionLocationDialog");
|
|
||||||
|
|
||||||
// Find the select option box
|
|
||||||
var selector = lesionDialog.find("select#selectLesionLocation");
|
|
||||||
|
|
||||||
// Find out if this lesion number is already added in the lesion manager for another timepoint
|
|
||||||
// If it is, stop here because we don't need the dialog.
|
|
||||||
var locationUID = measurementManagerDAL.lesionNumberExists(measurementData);
|
|
||||||
if (locationUID) {
|
|
||||||
measurementData.locationUID = locationUID;
|
|
||||||
measurementManagerDAL.updateTimepointData(measurementData);
|
|
||||||
closeHandler();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If it isn't, continue to open the dialog and have the user choose a lesion location
|
|
||||||
|
|
||||||
// Attach close handler if the user clicks the close button
|
|
||||||
var close = lesionDialog.find("#btnCloseLesionPopup");
|
|
||||||
close.off('click');
|
|
||||||
close.on('click', function() {
|
|
||||||
closeHandler();
|
|
||||||
});
|
|
||||||
|
|
||||||
function closeHandler() {
|
|
||||||
// Hide the lesion dialog
|
|
||||||
lesionDialog.css('display', 'none');
|
|
||||||
|
|
||||||
// Select the first option for the next time the dialog is opened
|
|
||||||
selector.find("option:first").prop("selected", true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach keypress handlers so the user can close with the Enter button
|
|
||||||
lesionDialog.off("keypress");
|
|
||||||
lesionDialog.on('keypress', keyPressHandler);
|
|
||||||
|
|
||||||
// This is the keypress callback function
|
|
||||||
function keyPressHandler(e) {
|
|
||||||
// If Enter is pressed, close the dialog
|
|
||||||
if (e.which === 13) {
|
|
||||||
closeHandler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the lesion location dialog above
|
|
||||||
|
|
||||||
var dialogProperty = {
|
|
||||||
top: eventData.currentPoints.page.y - lesionDialog.outerHeight() - 40,
|
|
||||||
left: eventData.currentPoints.page.x - lesionDialog.outerWidth() / 2,
|
|
||||||
display: 'block'
|
|
||||||
};
|
|
||||||
|
|
||||||
// Device is touch device or not
|
|
||||||
// If device is touch device, set position center of screen vertically and horizontally
|
|
||||||
if (isTouchDevice()) {
|
|
||||||
// add dialogMobile class to provide a black,transparent background
|
|
||||||
$(lesionDialog).addClass("dialogMobile");
|
|
||||||
dialogProperty.top = 0;
|
|
||||||
dialogProperty.left = 0;
|
|
||||||
dialogProperty.right = 0;
|
|
||||||
dialogProperty.bottom = 0;
|
|
||||||
$(".lesionContentWrapper").css({
|
|
||||||
left: ($(window).width() - $(".lesionContentWrapper").width()) / 2,
|
|
||||||
top: ($(window).height() - $(".lesionContentWrapper").height()) / 2
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
lesionDialog.css(dialogProperty);
|
|
||||||
|
|
||||||
// Attach a callback for the select box
|
|
||||||
selector.off('change');
|
|
||||||
selector.on('change', function(e) {
|
|
||||||
// Get the current value of the selector
|
|
||||||
var selectedOptionId = this.value;
|
|
||||||
|
|
||||||
// If the selected option is still the default (-1)
|
|
||||||
// then stop here
|
|
||||||
if (selectedOptionId < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get selected location data
|
|
||||||
var locationObj = LesionLocations.findOne({_id: selectedOptionId});
|
|
||||||
|
|
||||||
|
|
||||||
var id;
|
|
||||||
var existingLocation = PatientLocations.findOne({location: locationObj.location});
|
|
||||||
if (existingLocation) {
|
|
||||||
id = existingLocation._id;
|
|
||||||
} else {
|
|
||||||
// Adds location data to PatientLocation and retrieve the location ID
|
|
||||||
id = PatientLocations.insert({location: locationObj.location});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link locationUID with active lesion measurementData
|
|
||||||
measurementData.locationUID = id;
|
|
||||||
|
|
||||||
/// Set the isTarget value to true, since this is the target-lesion dialog callback
|
|
||||||
measurementData.isTarget = true;
|
|
||||||
|
|
||||||
// Adds lesion data to timepoints array
|
|
||||||
measurementManagerDAL.addLesionData(measurementData);
|
|
||||||
|
|
||||||
// Close the dialog
|
|
||||||
closeHandler();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeLesionLocationCallback(measurementData, eventData, doneCallback) {
|
|
||||||
doneCallback(prompt('Change your lesion location:'));
|
|
||||||
}
|
|
||||||
|
|
||||||
var config = {
|
|
||||||
setLesionNumberCallback: setLesionNumberCallback,
|
|
||||||
getLesionLocationCallback: getLesionLocationCallback,
|
|
||||||
changeLesionLocationCallback: changeLesionLocationCallback
|
|
||||||
};
|
|
||||||
|
|
||||||
cornerstoneTools.lesion.setConfiguration(config);
|
|
||||||
|
|
||||||
|
|
||||||
LesionLocations = new Meteor.Collection(null);
|
|
||||||
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Liver Left",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Liver Right",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Liver Caudate",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Lung LLL",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Lung LUL",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Lung RLL",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Lung RML",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Lung RUL",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Pleura Left",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Pleura Right",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Kidney Left",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
LesionLocations.insert({
|
|
||||||
location: "Kidney Right",
|
|
||||||
hasDescription: false,
|
|
||||||
description: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.lesionLocationDialog.helpers({
|
|
||||||
'lesionLocations': function() {
|
|
||||||
return LesionLocations.find();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
#lesionLocationDialog
|
|
||||||
display: none
|
|
||||||
position: absolute
|
|
||||||
z-index: 100
|
|
||||||
|
|
||||||
/* dialogMobile is added to #lesionLocationDialog when touchDevices is detected */
|
|
||||||
.dialogMobile
|
|
||||||
margin: 0 auto;
|
|
||||||
float: none;
|
|
||||||
background-color: rgba(0,0,0,0.5);
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
.lesionContentWrapper
|
|
||||||
position: absolute;
|
|
||||||
width: 250px;
|
|
||||||
height: 150px;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px 20px 10px 20px;
|
|
||||||
background-color: rgba(255,255,255,1);
|
|
||||||
text-align: left
|
|
||||||
|
|
||||||
#closeLesionPopup
|
|
||||||
outline: 0
|
|
||||||
border: none
|
|
||||||
background-color: transparent
|
|
||||||
|
|
||||||
#selectLesionLocation
|
|
||||||
margin-top: 5px
|
|
||||||
|
|
||||||
.dialogContent
|
|
||||||
margin-bottom: 20px
|
|
||||||
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
#nonTargetLesionLocationDialog {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dialogMobile is added to #nonTargetLesionLocationDialog when touchDevices is detected */
|
|
||||||
.dialogMobile {
|
|
||||||
margin: 0 auto;
|
|
||||||
float: none;
|
|
||||||
background-color: rgba(0,0,0,0.5);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contentWrapper {
|
|
||||||
position: absolute;
|
|
||||||
width: 250px;
|
|
||||||
height: 250px;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px 20px 10px 20px;
|
|
||||||
background-color: rgba(255,255,255,1);
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#selectNonTargetLesionLocation, #selectNonTargetLesionLocationResponse {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialogContent, .lesionLocation, .locationResponse {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.elementContainer {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
float: none;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.locationOK {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn{
|
|
||||||
background-color: #bbb;
|
|
||||||
border: 1px solid #888;
|
|
||||||
color: #000000;
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
<template name="nonTargetLesionDialog">
|
|
||||||
<div id="nonTargetLesionLocationDialog">
|
|
||||||
<div class="contentWrapper">
|
|
||||||
<div class="dialogHeader">
|
|
||||||
<div class="dialogHeader">
|
|
||||||
<div><h4>Select Lesion Location</h4></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="dialogContent">
|
|
||||||
<div class="lesionLocation">
|
|
||||||
<div class="elementContainer">
|
|
||||||
<label>Lesion Location</label>
|
|
||||||
</div>
|
|
||||||
<div class="elementContainer">
|
|
||||||
<select id="selectNonTargetLesionLocation">
|
|
||||||
<option value="-1"></option>
|
|
||||||
{{ #each lesionLocations}}
|
|
||||||
<option value='{{_id}}'>{{location}}</option>
|
|
||||||
{{ /each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="locationResponse">
|
|
||||||
<div class="elementContainer">
|
|
||||||
<label>Response</label>
|
|
||||||
</div>
|
|
||||||
<div class="elementContainer">
|
|
||||||
<select id="selectNonTargetLesionLocationResponse">
|
|
||||||
<option value="-1"></option>
|
|
||||||
{{ #each locationResponses}}
|
|
||||||
<option value='{{code}}'>{{code}} - {{text}}</option>
|
|
||||||
{{ /each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="locationOK">
|
|
||||||
<button class="btn" id="nonTargetLesionOK">OK</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
@ -17,38 +17,41 @@ Package.onUse(function (api) {
|
|||||||
|
|
||||||
api.addFiles('log.js', ['client', 'server']);
|
api.addFiles('log.js', ['client', 'server']);
|
||||||
|
|
||||||
api.addFiles('compatibility/lesionTool.js', 'client', {bare: true});
|
api.addFiles('client/collections/LesionLocations.js', 'client');
|
||||||
api.addFiles('compatibility/nonTargetTool.js', 'client', {bare: true});
|
api.addFiles('client/collections/LocationResponses.js', 'client');
|
||||||
api.addFiles('compatibility/measurementManagerDAL.js', 'client', {bare: true});
|
|
||||||
|
|
||||||
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.html', 'client');
|
api.addFiles('client/compatibility/lesionTool.js', 'client', {bare: true});
|
||||||
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.js', 'client');
|
api.addFiles('client/compatibility/nonTargetTool.js', 'client', {bare: true});
|
||||||
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.styl', 'client');
|
api.addFiles('client/compatibility/measurementManagerDAL.js', 'client', {bare: true});
|
||||||
|
|
||||||
api.addFiles('components/lesionTable/lesionTable.html', 'client');
|
api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.html', 'client');
|
||||||
api.addFiles('components/lesionTable/lesionTable.styl', 'client');
|
api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.js', 'client');
|
||||||
api.addFiles('components/lesionTable/lesionTable.js', 'client');
|
api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.styl', 'client');
|
||||||
|
|
||||||
api.addFiles('components/lesionTableRow/lesionTableRow.html', 'client');
|
api.addFiles('client/components/lesionTable/lesionTable.html', 'client');
|
||||||
api.addFiles('components/lesionTableRow/lesionTableRow.js', 'client');
|
api.addFiles('client/components/lesionTable/lesionTable.styl', 'client');
|
||||||
|
api.addFiles('client/components/lesionTable/lesionTable.js', 'client');
|
||||||
|
|
||||||
api.addFiles('components/lesionTableTimepointCell/lesionTableTimepointCell.html', 'client');
|
api.addFiles('client/components/lesionTableRow/lesionTableRow.html', 'client');
|
||||||
api.addFiles('components/lesionTableTimepointCell/lesionTableTimepointCell.js', 'client');
|
api.addFiles('client/components/lesionTableRow/lesionTableRow.js', 'client');
|
||||||
|
|
||||||
api.addFiles('components/lesionTableTimepointHeader/lesionTableTimepointHeader.html', 'client');
|
api.addFiles('client/components/lesionTableTimepointCell/lesionTableTimepointCell.html', 'client');
|
||||||
api.addFiles('components/lesionTableTimepointHeader/lesionTableTimepointHeader.js', 'client');
|
api.addFiles('client/components/lesionTableTimepointCell/lesionTableTimepointCell.js', 'client');
|
||||||
api.addFiles('components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl', 'client');
|
|
||||||
|
|
||||||
api.addFiles('components/nonTargetLesionDialog/nonTargetLesionDialog.html', 'client');
|
api.addFiles('client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.html', 'client');
|
||||||
api.addFiles('components/nonTargetLesionDialog/nonTargetLesionDialog.css', 'client');
|
api.addFiles('client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.js', 'client');
|
||||||
api.addFiles('components/nonTargetLesionDialog/nonTargetLesionDialog.js', 'client');
|
api.addFiles('client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl', 'client');
|
||||||
|
|
||||||
api.addFiles('components/studyDateList/studyDateList.html', 'client');
|
api.addFiles('client/components/nonTargetLesionDialog/nonTargetLesionDialog.html', 'client');
|
||||||
api.addFiles('components/studyDateList/studyDateList.styl', 'client');
|
api.addFiles('client/components/nonTargetLesionDialog/nonTargetLesionDialog.styl', 'client');
|
||||||
api.addFiles('components/studyDateList/studyDateList.js', 'client');
|
api.addFiles('client/components/nonTargetLesionDialog/nonTargetLesionDialog.js', 'client');
|
||||||
|
|
||||||
api.addFiles('components/timepointTextDialog/timepointTextDialog.html', 'client');
|
api.addFiles('client/components/studyDateList/studyDateList.html', 'client');
|
||||||
api.addFiles('components/timepointTextDialog/timepointTextDialog.styl', 'client');
|
api.addFiles('client/components/studyDateList/studyDateList.styl', 'client');
|
||||||
|
api.addFiles('client/components/studyDateList/studyDateList.js', 'client');
|
||||||
|
|
||||||
|
api.addFiles('client/components/timepointTextDialog/timepointTextDialog.html', 'client');
|
||||||
|
api.addFiles('client/components/timepointTextDialog/timepointTextDialog.styl', 'client');
|
||||||
|
|
||||||
// Server functions
|
// Server functions
|
||||||
api.addFiles('server/collections.js', 'server');
|
api.addFiles('server/collections.js', 'server');
|
||||||
@ -57,7 +60,6 @@ Package.onUse(function (api) {
|
|||||||
// Both client and server functions
|
// Both client and server functions
|
||||||
api.addFiles('both/collections.js', ['client', 'server']);
|
api.addFiles('both/collections.js', ['client', 'server']);
|
||||||
|
|
||||||
|
|
||||||
// Library functions
|
// Library functions
|
||||||
api.addFiles('lib/uuid.js', 'client');
|
api.addFiles('lib/uuid.js', 'client');
|
||||||
api.addFiles('lib/resizeViewportElements.js', 'client');
|
api.addFiles('lib/resizeViewportElements.js', 'client');
|
||||||
@ -66,7 +68,14 @@ Package.onUse(function (api) {
|
|||||||
// Export lesionTable function for activate measurements
|
// Export lesionTable function for activate measurements
|
||||||
api.export('activateLesion','client');
|
api.export('activateLesion','client');
|
||||||
api.export('resizeViewportElements','client');
|
api.export('resizeViewportElements','client');
|
||||||
|
api.export('measurementManagerDAL', 'client');
|
||||||
|
|
||||||
|
// Export client-side collections
|
||||||
|
api.export('LesionLocations', 'client');
|
||||||
|
api.export('LocationResponses', 'client');
|
||||||
|
api.export('PatientLocations', 'client');
|
||||||
|
|
||||||
|
// Export collections spanning both client and server
|
||||||
api.export('Measurements', ['client', 'server']);
|
api.export('Measurements', ['client', 'server']);
|
||||||
api.export('Timepoints', ['client', 'server']);
|
api.export('Timepoints', ['client', 'server']);
|
||||||
});
|
});
|
||||||
@ -121,7 +121,7 @@ var savedSeriesData,
|
|||||||
savedViewportColumns;
|
savedViewportColumns;
|
||||||
|
|
||||||
Template.imageViewerViewports.events({
|
Template.imageViewerViewports.events({
|
||||||
'dblclick .imageViewerViewport': function(e) {
|
'CornerstoneMouseDoubleClick .imageViewerViewport': function(e) {
|
||||||
var container = $(".viewerMain").get(0);
|
var container = $(".viewerMain").get(0);
|
||||||
var data;
|
var data;
|
||||||
var contentId = this.contentId || $("#viewer").parents(".tab-pane.active").attr('id');
|
var contentId = this.contentId || $("#viewer").parents(".tab-pane.active").attr('id');
|
||||||
@ -140,7 +140,7 @@ Template.imageViewerViewports.events({
|
|||||||
|
|
||||||
data = {
|
data = {
|
||||||
viewportRows: ViewerData[contentId].viewportRows,
|
viewportRows: ViewerData[contentId].viewportRows,
|
||||||
viewportColumns: ViewerData[contentId].viewportColumns,
|
viewportColumns: ViewerData[contentId].viewportColumns
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render the imageViewerViewports template with these settings
|
// Render the imageViewerViewports template with these settings
|
||||||
@ -181,7 +181,6 @@ Template.imageViewerViewports.events({
|
|||||||
|
|
||||||
// Add the 'zoomed' class to the lone remaining viewport
|
// Add the 'zoomed' class to the lone remaining viewport
|
||||||
$('.imageViewerViewport').eq(0).addClass('zoomed');
|
$('.imageViewerViewport').eq(0).addClass('zoomed');
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1,3 +1,3 @@
|
|||||||
// Create package logger using loglevel
|
// Create package logger using loglevel
|
||||||
// https://atmospherejs.com/spacejamio/loglevel
|
// https://atmospherejs.com/spacejamio/loglevel
|
||||||
log = loglevel.createPackageLogger('viewerbase', defaultLevel = 'info');
|
log = loglevel.createPackageLogger('viewerbase', defaultLevel = 'warn');
|
||||||
@ -4,7 +4,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Orthanc",
|
"name": "Orthanc",
|
||||||
"wadoUriRootNOTE" : "either this uri is not correct for wado-uri or wado-uri is not configured on orthanc currently",
|
"wadoUriRootNOTE" : "either this uri is not correct for wado-uri or wado-uri is not configured on orthanc currently",
|
||||||
"wadoUriRoot" : "http://localhost:8042/wado",
|
"wadoUriRoot" : "http://localhost:8043/wado",
|
||||||
"qidoRoot": "http://localhost:8042/dicom-web",
|
"qidoRoot": "http://localhost:8042/dicom-web",
|
||||||
"wadoRoot": "http://localhost:8042/dicom-web",
|
"wadoRoot": "http://localhost:8042/dicom-web",
|
||||||
"qidoSupportsIncludeField": false,
|
"qidoSupportsIncludeField": false,
|
||||||
|
|||||||
20
etc/OrthancProxy.js
Normal file
20
etc/OrthancProxy.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// This sets up a proxy to work around CORS.
|
||||||
|
// See http://chafey.blogspot.be/2014/09/working-around-cors.html
|
||||||
|
// For more information
|
||||||
|
var http = require('http'),
|
||||||
|
httpProxy = require('http-proxy');
|
||||||
|
|
||||||
|
var proxy = httpProxy.createProxyServer({
|
||||||
|
target: 'http://localhost:8042',
|
||||||
|
auth: 'orthanc:orthanc'
|
||||||
|
}).listen(8043);
|
||||||
|
|
||||||
|
proxy.on('proxyRes', function(proxyReq, req, res, options) {
|
||||||
|
// add the CORS header to the response
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
});
|
||||||
|
|
||||||
|
proxy.on('error', function(e) {
|
||||||
|
// suppress errors
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user