From da197368bf9939c7bf73107c8873190c8fd02ec2 Mon Sep 17 00:00:00 2001 From: Erik Ziegler Date: Mon, 7 Dec 2015 17:15:14 +0100 Subject: [PATCH] Add some WIP changes to Lesion Tracker dialogs --- LesionTracker/client/components/viewer.js | 151 ++++++++--- .../client/collections/LesionLocations.js | 108 ++++++++ .../client/collections/LocationResponses.js | 55 ++++ .../{ => client}/compatibility/lesionTool.js | 62 ++++- .../compatibility/measurementManagerDAL.js | 10 +- .../compatibility/nonTargetTool.js | 3 +- .../lesionLocationDialog.html | 37 +++ .../lesionLocationDialog.js | 247 ++++++++++++++++++ .../lesionLocationDialog.styl | 40 +++ .../components/lesionTable/lesionTable.html | 0 .../components/lesionTable/lesionTable.js | 16 +- .../components/lesionTable/lesionTable.styl | 0 .../lesionTableRow/lesionTableRow.html | 0 .../lesionTableRow/lesionTableRow.js | 0 .../lesionTableTimepointCell.html | 0 .../lesionTableTimepointCell.js | 0 .../lesionTableTimepointHeader.html | 0 .../lesionTableTimepointHeader.js | 0 .../lesionTableTimepointHeader.styl | 0 .../nonTargetLesionDialog.html | 40 +++ .../nonTargetLesionDialog.js | 247 ++++++++---------- .../nonTargetLesionDialog.styl | 35 +++ .../studyDateList/studyDateList.html | 0 .../components/studyDateList/studyDateList.js | 0 .../studyDateList/studyDateList.styl | 0 .../timepointTextDialog.html | 0 .../timepointTextDialog.styl | 0 .../lesionLocationDialog.html | 20 -- .../lesionLocationDialog.js | 226 ---------------- .../lesionLocationDialog.styl | 32 --- .../nonTargetLesionDialog.css | 48 ---- .../nonTargetLesionDialog.html | 45 ---- Packages/lesiontracker/package.js | 59 +++-- .../imageViewerViewports.js | 5 +- Packages/viewerbase/log.js | 2 +- config/localhostOrthanc.json | 2 +- etc/OrthancProxy.js | 20 ++ 37 files changed, 915 insertions(+), 595 deletions(-) create mode 100644 Packages/lesiontracker/client/collections/LesionLocations.js create mode 100644 Packages/lesiontracker/client/collections/LocationResponses.js rename Packages/lesiontracker/{ => client}/compatibility/lesionTool.js (85%) rename Packages/lesiontracker/{ => client}/compatibility/measurementManagerDAL.js (94%) rename Packages/lesiontracker/{ => client}/compatibility/nonTargetTool.js (99%) create mode 100644 Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.html create mode 100644 Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.js create mode 100644 Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.styl rename Packages/lesiontracker/{ => client}/components/lesionTable/lesionTable.html (100%) rename Packages/lesiontracker/{ => client}/components/lesionTable/lesionTable.js (94%) rename Packages/lesiontracker/{ => client}/components/lesionTable/lesionTable.styl (100%) rename Packages/lesiontracker/{ => client}/components/lesionTableRow/lesionTableRow.html (100%) rename Packages/lesiontracker/{ => client}/components/lesionTableRow/lesionTableRow.js (100%) rename Packages/lesiontracker/{ => client}/components/lesionTableTimepointCell/lesionTableTimepointCell.html (100%) rename Packages/lesiontracker/{ => client}/components/lesionTableTimepointCell/lesionTableTimepointCell.js (100%) rename Packages/lesiontracker/{ => client}/components/lesionTableTimepointHeader/lesionTableTimepointHeader.html (100%) rename Packages/lesiontracker/{ => client}/components/lesionTableTimepointHeader/lesionTableTimepointHeader.js (100%) rename Packages/lesiontracker/{ => client}/components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl (100%) create mode 100644 Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.html rename Packages/lesiontracker/{ => client}/components/nonTargetLesionDialog/nonTargetLesionDialog.js (55%) create mode 100644 Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.styl rename Packages/lesiontracker/{ => client}/components/studyDateList/studyDateList.html (100%) rename Packages/lesiontracker/{ => client}/components/studyDateList/studyDateList.js (100%) rename Packages/lesiontracker/{ => client}/components/studyDateList/studyDateList.styl (100%) rename Packages/lesiontracker/{ => client}/components/timepointTextDialog/timepointTextDialog.html (100%) rename Packages/lesiontracker/{ => client}/components/timepointTextDialog/timepointTextDialog.styl (100%) delete mode 100644 Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.html delete mode 100644 Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.js delete mode 100644 Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.styl delete mode 100644 Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.css delete mode 100644 Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.html create mode 100644 etc/OrthancProxy.js diff --git a/LesionTracker/client/components/viewer.js b/LesionTracker/client/components/viewer.js index 4119605ca..43b4d63b7 100644 --- a/LesionTracker/client/components/viewer.js +++ b/LesionTracker/client/components/viewer.js @@ -51,12 +51,6 @@ Template.viewer.onCreated(function() { } OHIF.viewer.isPlaying[viewportIndex] = !OHIF.viewer.isPlaying[viewportIndex]; 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; Session.set('patientId', patientId); - initialized = false; self.autorun(function() { var patientId = Session.get('patientId'); self.subscribe('timepoints', patientId); @@ -113,38 +106,35 @@ Template.viewer.onCreated(function() { return; } - if (initialized === true) { - return; - } + ViewerStudies.find().observe({ + 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 timepoint = Timepoints.findOne({timepointName: study.studyDate}); - if (timepoint) { - log.warn("A timepoint with that study date already exists!"); - return; + 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 + }); } - - 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 // Cornerstone ToolData structure Measurements.find().observe({ added: function (data) { - if (data.toolDataInsertedManually === true) { // Activate first measurements in image box as default if exists @@ -156,19 +146,40 @@ Template.viewer.onCreated(function() { } return; } - log.info('Measurement added'); 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); }); +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) { // Check what toolType we should be adding this to, based on the isTarget value // of the stored Measurement @@ -184,10 +195,41 @@ function addMeasurementAsToolData(data) { 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]) { toolState[imageId][toolType] = { 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 @@ -204,6 +246,7 @@ function addMeasurementAsToolData(data) { measurementData.visible = data.visible; measurementData.active = data.active; measurementData.uid = data.uid; + measurementData.id = data._id; toolState[imageId][toolType].data.push(measurementData); }); @@ -215,6 +258,46 @@ Template.viewer.onDestroyed(function() { 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 // because it is fired very often. // Resizing is therefore performed 100 ms after the resize event stops. diff --git a/Packages/lesiontracker/client/collections/LesionLocations.js b/Packages/lesiontracker/client/collections/LesionLocations.js new file mode 100644 index 000000000..f2ae38e5d --- /dev/null +++ b/Packages/lesiontracker/client/collections/LesionLocations.js @@ -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: "" +}); \ No newline at end of file diff --git a/Packages/lesiontracker/client/collections/LocationResponses.js b/Packages/lesiontracker/client/collections/LocationResponses.js new file mode 100644 index 000000000..485bd6cc4 --- /dev/null +++ b/Packages/lesiontracker/client/collections/LocationResponses.js @@ -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: "" +}); \ No newline at end of file diff --git a/Packages/lesiontracker/compatibility/lesionTool.js b/Packages/lesiontracker/client/compatibility/lesionTool.js similarity index 85% rename from Packages/lesiontracker/compatibility/lesionTool.js rename to Packages/lesiontracker/client/compatibility/lesionTool.js index 356c22c55..06dc959e4 100644 --- a/Packages/lesiontracker/compatibility/lesionTool.js +++ b/Packages/lesiontracker/client/compatibility/lesionTool.js @@ -71,7 +71,7 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo cornerstoneTools.removeToolState(element, toolType, measurementData); } else { // Set lesionMeasurementData Session - config.getLesionLocationCallback(measurementData, mouseEventData); + config.getLesionLocationCallback(measurementData, mouseEventData, doneCallback); } $(element).on('CornerstoneToolsMouseMove', eventData, cornerstoneTools.lesion.mouseMoveCallback); @@ -157,7 +157,8 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo pointNearHandle: pointNearTextBox, active: false, movesIndependently: true, - drawnIndependently: true + drawnIndependently: true, + allowedOutsideImage: true } }, imageId: imageId, @@ -282,10 +283,7 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo // Set measurement text to show lesion table data.measurementText = length.toFixed(1); - 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 cornerstoneTools.lesion = cornerstoneTools.mouseButtonTool({ @@ -309,6 +358,7 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo addNewMeasurement: addNewMeasurement, onImageRendered: onImageRendered, pointNearTool: pointNearTool, + mouseDoubleClickCallback: doubleClickCallback, toolType: toolType }); diff --git a/Packages/lesiontracker/compatibility/measurementManagerDAL.js b/Packages/lesiontracker/client/compatibility/measurementManagerDAL.js similarity index 94% rename from Packages/lesiontracker/compatibility/measurementManagerDAL.js rename to Packages/lesiontracker/client/compatibility/measurementManagerDAL.js index 175a9445e..423e3a2d5 100644 --- a/Packages/lesiontracker/compatibility/measurementManagerDAL.js +++ b/Packages/lesiontracker/client/compatibility/measurementManagerDAL.js @@ -46,12 +46,9 @@ var measurementManagerDAL = (function() { lesionDataObject.timepoints = timepointsObject; // 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.toolDataInsertedManually = true; - - Measurements.insert(lesionDataObject); + lesionDataObject.id = Measurements.insert(lesionDataObject); } // Update timepoint data in Measurements collection @@ -82,6 +79,7 @@ var measurementManagerDAL = (function() { timepoints[timepointID].studyInstanceUid = lesionData.studyInstanceUid; timepoints[timepointID].handles = lesionData.handles; + lesionData.id = measurement._id; Measurements.update(measurement._id, { $set: { @@ -133,7 +131,7 @@ var measurementManagerDAL = (function() { if (!timepoints[timepointID]) { // Find lesion number for this timepointID - return measurement.lesionNumber + return measurement.lesionNumber; } if (timepoints[timepointID].longestDiameter === '') { diff --git a/Packages/lesiontracker/compatibility/nonTargetTool.js b/Packages/lesiontracker/client/compatibility/nonTargetTool.js similarity index 99% rename from Packages/lesiontracker/compatibility/nonTargetTool.js rename to Packages/lesiontracker/client/compatibility/nonTargetTool.js index 6b57c6770..26f3414e2 100644 --- a/Packages/lesiontracker/compatibility/nonTargetTool.js +++ b/Packages/lesiontracker/client/compatibility/nonTargetTool.js @@ -118,7 +118,8 @@ pointNearHandle: pointNearTextBox, active: false, movesIndependently: true, - drawnIndependently: true + drawnIndependently: true, + allowedOutsideImage: true } }, imageId: imageId, diff --git a/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.html b/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.html new file mode 100644 index 000000000..ed3b15d86 --- /dev/null +++ b/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.html @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.js b/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.js new file mode 100644 index 000000000..9f2f4bf89 --- /dev/null +++ b/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.js @@ -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(); + } +}); \ No newline at end of file diff --git a/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.styl b/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.styl new file mode 100644 index 000000000..172924edf --- /dev/null +++ b/Packages/lesiontracker/client/components/lesionLocationDialog/lesionLocationDialog.styl @@ -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 \ No newline at end of file diff --git a/Packages/lesiontracker/components/lesionTable/lesionTable.html b/Packages/lesiontracker/client/components/lesionTable/lesionTable.html similarity index 100% rename from Packages/lesiontracker/components/lesionTable/lesionTable.html rename to Packages/lesiontracker/client/components/lesionTable/lesionTable.html diff --git a/Packages/lesiontracker/components/lesionTable/lesionTable.js b/Packages/lesiontracker/client/components/lesionTable/lesionTable.js similarity index 94% rename from Packages/lesiontracker/components/lesionTable/lesionTable.js rename to Packages/lesiontracker/client/components/lesionTable/lesionTable.js index 2b1020645..a9005b906 100644 --- a/Packages/lesiontracker/components/lesionTable/lesionTable.js +++ b/Packages/lesiontracker/client/components/lesionTable/lesionTable.js @@ -41,6 +41,11 @@ activateLesion = function(measurementId, templateData) { $(".imageViewerViewport").each(function(viewportIndex, element) { // Stop if we run out of timepoints before viewports 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; } @@ -57,6 +62,10 @@ activateLesion = function(measurementId, templateData) { // If there is no measurement data to display, stop here if (!measurementAtTimepoint) { + // Update the element anyway, to remove any other highlights that are present + deactivateAllToolData(element, 'lesion'); + deactivateAllToolData(element, 'nonTarget'); + cornerstone.updateImage(element); return; } @@ -247,7 +256,6 @@ Template.lesionTable.events({ }); } - }); Template.lesionTable.onCreated(function(){ @@ -275,14 +283,13 @@ Tracker.autorun(function () { dates: [] }; - $("#"+contentId+" .imageViewerViewport").each(function(viewportIndex, element) { + $(".imageViewerViewport").each(function(viewportIndex, element) { var enabledElement = cornerstone.getEnabledElement(element); if(enabledElement && enabledElement.image){ var imageId = enabledElement.image.imageId; var study = cornerstoneTools.metaData.get('study', imageId); var studyDate = study.studyDate; - var patientId = study.patientId; - loadedStudyDates.patientId = patientId; + loadedStudyDates.patientId = study.patientId; // Check studyDate is added before if (loadedStudyDates.dates.indexOf(studyDate) < 0) { loadedStudyDates.dates.push(studyDate); @@ -306,7 +313,6 @@ Tracker.autorun(function () { $set: { timepointLoaded: timepointLoaded } - }); }); } diff --git a/Packages/lesiontracker/components/lesionTable/lesionTable.styl b/Packages/lesiontracker/client/components/lesionTable/lesionTable.styl similarity index 100% rename from Packages/lesiontracker/components/lesionTable/lesionTable.styl rename to Packages/lesiontracker/client/components/lesionTable/lesionTable.styl diff --git a/Packages/lesiontracker/components/lesionTableRow/lesionTableRow.html b/Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.html similarity index 100% rename from Packages/lesiontracker/components/lesionTableRow/lesionTableRow.html rename to Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.html diff --git a/Packages/lesiontracker/components/lesionTableRow/lesionTableRow.js b/Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.js similarity index 100% rename from Packages/lesiontracker/components/lesionTableRow/lesionTableRow.js rename to Packages/lesiontracker/client/components/lesionTableRow/lesionTableRow.js diff --git a/Packages/lesiontracker/components/lesionTableTimepointCell/lesionTableTimepointCell.html b/Packages/lesiontracker/client/components/lesionTableTimepointCell/lesionTableTimepointCell.html similarity index 100% rename from Packages/lesiontracker/components/lesionTableTimepointCell/lesionTableTimepointCell.html rename to Packages/lesiontracker/client/components/lesionTableTimepointCell/lesionTableTimepointCell.html diff --git a/Packages/lesiontracker/components/lesionTableTimepointCell/lesionTableTimepointCell.js b/Packages/lesiontracker/client/components/lesionTableTimepointCell/lesionTableTimepointCell.js similarity index 100% rename from Packages/lesiontracker/components/lesionTableTimepointCell/lesionTableTimepointCell.js rename to Packages/lesiontracker/client/components/lesionTableTimepointCell/lesionTableTimepointCell.js diff --git a/Packages/lesiontracker/components/lesionTableTimepointHeader/lesionTableTimepointHeader.html b/Packages/lesiontracker/client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.html similarity index 100% rename from Packages/lesiontracker/components/lesionTableTimepointHeader/lesionTableTimepointHeader.html rename to Packages/lesiontracker/client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.html diff --git a/Packages/lesiontracker/components/lesionTableTimepointHeader/lesionTableTimepointHeader.js b/Packages/lesiontracker/client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.js similarity index 100% rename from Packages/lesiontracker/components/lesionTableTimepointHeader/lesionTableTimepointHeader.js rename to Packages/lesiontracker/client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.js diff --git a/Packages/lesiontracker/components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl b/Packages/lesiontracker/client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl similarity index 100% rename from Packages/lesiontracker/components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl rename to Packages/lesiontracker/client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl diff --git a/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.html b/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.html new file mode 100644 index 000000000..44575ec7b --- /dev/null +++ b/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.html @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.js b/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.js similarity index 55% rename from Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.js rename to Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.js index f5946a44b..deafa1b60 100644 --- a/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.js +++ b/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.js @@ -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) { // Get the current element's timepointID from the study date metadata 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 // If there already exists a lesion with this specific lesion number, // related to the chosen location. - function getNonTargetLesionLocationCallback(measurementData, eventData) { + Template.nonTargetLesionDialog.measurementData = measurementData; // 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 - var selectorLocation = nonTargetlesionDialog.find("select#selectNonTargetLesionLocation"); - var selectorResponse = nonTargetlesionDialog.find("select#selectNonTargetLesionLocationResponse"); + var selectorLocation = dialog.find("select#selectNonTargetLesionLocation"); + var selectorResponse = dialog.find("select#selectNonTargetLesionLocationResponse"); - // OK button - var btnOK = nonTargetlesionDialog.find("button#nonTargetLesionOK"); + selectorLocation.find("option:first").prop("selected", "selected"); + selectorResponse.find("option:first").prop("selected", "selected"); - - // If selector location is disabled, make it enable - enableLocationSelection(); + // Allow location selection + selectorLocation.removeAttr("disabled"); // Find out if this lesion number is already added in the lesion manager for another timepoint // If it is, disable selector location 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; // Disable the selection of a new location disableLocationSelection(measurementData.locationUID); @@ -58,48 +81,16 @@ function getNonTargetLesionLocationCallback(measurementData, eventData) { // Disable selector location to prevent selecting a new location function disableLocationSelection(locationUID) { var locationName = measurementManagerDAL.getLocationName(locationUID); - selectorLocation.find('option').each(function() - { + selectorLocation.find('option').each(function() { if ($(this).text() === locationName) { // Select location in locations dropdown list selectorLocation.find('option').eq($(this).index()).prop("selected", true); - return; } }); 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 var dialogProperty = { 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 (isTouchDevice()) { // add dialogMobile class to provide a black,transparent background - $(nonTargetlesionDialog).addClass("dialogMobile"); + dialog.addClass("dialogMobile"); dialogProperty.top = 0; dialogProperty.left = 0; dialogProperty.right = 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 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) // then stop here @@ -141,7 +145,7 @@ function getNonTargetLesionLocationCallback(measurementData, eventData) { // If the selected response option is still the default (-1) // then stop here - if (responseOptionCode < 0) { + if (responseOptionId < 0) { return; } @@ -157,102 +161,61 @@ function getNonTargetLesionLocationCallback(measurementData, eventData) { id = PatientLocations.insert({location: locationObj.location}); } - // Link locationUID with active lesion measurementData - measurementData.locationUID = id; + if (!measurementData.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 - measurementData.isTarget = false; + // Link locationUID with active lesion measurementData + measurementData.locationUID = id; - // measurementText is set from location response list - measurementData.measurementText = responseOptionCode; + /// Set the isTarget value to true, since this is the target-lesion dialog callback + measurementData.isTarget = false; - // Adds lesion data to timepoints array - measurementManagerDAL.addLesionData(measurementData); + // measurementText is set from location response list + 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 - 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) { - doneCallback(prompt('Change your lesion location:')); -} + if (doneCallback && typeof doneCallback === 'function') { + var deleteTool = true; + doneCallback(measurementData, deleteTool); + } -var config = { - setLesionNumberCallback: setLesionNumberCallback, - getNonTargetLesionLocationCallback: getNonTargetLesionLocationCallback, - changeNonTargetLesionLocationCallback: changeNonTargetLesionLocationCallback -}; + closeHandler(dialog); + }, + 'click #btnCloseLesionPopup': function() { + 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({ 'lesionLocations': function() { return LesionLocations.find(); diff --git a/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.styl b/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.styl new file mode 100644 index 000000000..8ad3005af --- /dev/null +++ b/Packages/lesiontracker/client/components/nonTargetLesionDialog/nonTargetLesionDialog.styl @@ -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 + \ No newline at end of file diff --git a/Packages/lesiontracker/components/studyDateList/studyDateList.html b/Packages/lesiontracker/client/components/studyDateList/studyDateList.html similarity index 100% rename from Packages/lesiontracker/components/studyDateList/studyDateList.html rename to Packages/lesiontracker/client/components/studyDateList/studyDateList.html diff --git a/Packages/lesiontracker/components/studyDateList/studyDateList.js b/Packages/lesiontracker/client/components/studyDateList/studyDateList.js similarity index 100% rename from Packages/lesiontracker/components/studyDateList/studyDateList.js rename to Packages/lesiontracker/client/components/studyDateList/studyDateList.js diff --git a/Packages/lesiontracker/components/studyDateList/studyDateList.styl b/Packages/lesiontracker/client/components/studyDateList/studyDateList.styl similarity index 100% rename from Packages/lesiontracker/components/studyDateList/studyDateList.styl rename to Packages/lesiontracker/client/components/studyDateList/studyDateList.styl diff --git a/Packages/lesiontracker/components/timepointTextDialog/timepointTextDialog.html b/Packages/lesiontracker/client/components/timepointTextDialog/timepointTextDialog.html similarity index 100% rename from Packages/lesiontracker/components/timepointTextDialog/timepointTextDialog.html rename to Packages/lesiontracker/client/components/timepointTextDialog/timepointTextDialog.html diff --git a/Packages/lesiontracker/components/timepointTextDialog/timepointTextDialog.styl b/Packages/lesiontracker/client/components/timepointTextDialog/timepointTextDialog.styl similarity index 100% rename from Packages/lesiontracker/components/timepointTextDialog/timepointTextDialog.styl rename to Packages/lesiontracker/client/components/timepointTextDialog/timepointTextDialog.styl diff --git a/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.html b/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.html deleted file mode 100644 index 869487863..000000000 --- a/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.html +++ /dev/null @@ -1,20 +0,0 @@ - \ No newline at end of file diff --git a/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.js b/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.js deleted file mode 100644 index 9085a9041..000000000 --- a/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.js +++ /dev/null @@ -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(); - } -}); \ No newline at end of file diff --git a/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.styl b/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.styl deleted file mode 100644 index 6c62f51c3..000000000 --- a/Packages/lesiontracker/components/lesionLocationDialog/lesionLocationDialog.styl +++ /dev/null @@ -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 - diff --git a/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.css b/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.css deleted file mode 100644 index 36a555cfc..000000000 --- a/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.css +++ /dev/null @@ -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; -} diff --git a/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.html b/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.html deleted file mode 100644 index 095f5fed0..000000000 --- a/Packages/lesiontracker/components/nonTargetLesionDialog/nonTargetLesionDialog.html +++ /dev/null @@ -1,45 +0,0 @@ - \ No newline at end of file diff --git a/Packages/lesiontracker/package.js b/Packages/lesiontracker/package.js index 945c8c21b..753d0e741 100644 --- a/Packages/lesiontracker/package.js +++ b/Packages/lesiontracker/package.js @@ -17,38 +17,41 @@ Package.onUse(function (api) { api.addFiles('log.js', ['client', 'server']); - api.addFiles('compatibility/lesionTool.js', 'client', {bare: true}); - api.addFiles('compatibility/nonTargetTool.js', 'client', {bare: true}); - api.addFiles('compatibility/measurementManagerDAL.js', 'client', {bare: true}); + api.addFiles('client/collections/LesionLocations.js', 'client'); + api.addFiles('client/collections/LocationResponses.js', 'client'); - api.addFiles('components/lesionLocationDialog/lesionLocationDialog.html', 'client'); - api.addFiles('components/lesionLocationDialog/lesionLocationDialog.js', 'client'); - api.addFiles('components/lesionLocationDialog/lesionLocationDialog.styl', 'client'); + api.addFiles('client/compatibility/lesionTool.js', 'client', {bare: true}); + api.addFiles('client/compatibility/nonTargetTool.js', 'client', {bare: true}); + api.addFiles('client/compatibility/measurementManagerDAL.js', 'client', {bare: true}); + + api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.html', 'client'); + api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.js', 'client'); + api.addFiles('client/components/lesionLocationDialog/lesionLocationDialog.styl', 'client'); - api.addFiles('components/lesionTable/lesionTable.html', 'client'); - api.addFiles('components/lesionTable/lesionTable.styl', 'client'); - api.addFiles('components/lesionTable/lesionTable.js', 'client'); + api.addFiles('client/components/lesionTable/lesionTable.html', 'client'); + api.addFiles('client/components/lesionTable/lesionTable.styl', 'client'); + api.addFiles('client/components/lesionTable/lesionTable.js', 'client'); - api.addFiles('components/lesionTableRow/lesionTableRow.html', 'client'); - api.addFiles('components/lesionTableRow/lesionTableRow.js', 'client'); + api.addFiles('client/components/lesionTableRow/lesionTableRow.html', 'client'); + api.addFiles('client/components/lesionTableRow/lesionTableRow.js', 'client'); - api.addFiles('components/lesionTableTimepointCell/lesionTableTimepointCell.html', 'client'); - api.addFiles('components/lesionTableTimepointCell/lesionTableTimepointCell.js', 'client'); + api.addFiles('client/components/lesionTableTimepointCell/lesionTableTimepointCell.html', 'client'); + api.addFiles('client/components/lesionTableTimepointCell/lesionTableTimepointCell.js', 'client'); - api.addFiles('components/lesionTableTimepointHeader/lesionTableTimepointHeader.html', 'client'); - api.addFiles('components/lesionTableTimepointHeader/lesionTableTimepointHeader.js', 'client'); - api.addFiles('components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl', 'client'); + api.addFiles('client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.html', 'client'); + api.addFiles('client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.js', 'client'); + api.addFiles('client/components/lesionTableTimepointHeader/lesionTableTimepointHeader.styl', 'client'); - api.addFiles('components/nonTargetLesionDialog/nonTargetLesionDialog.html', 'client'); - api.addFiles('components/nonTargetLesionDialog/nonTargetLesionDialog.css', 'client'); - api.addFiles('components/nonTargetLesionDialog/nonTargetLesionDialog.js', 'client'); + api.addFiles('client/components/nonTargetLesionDialog/nonTargetLesionDialog.html', 'client'); + api.addFiles('client/components/nonTargetLesionDialog/nonTargetLesionDialog.styl', 'client'); + api.addFiles('client/components/nonTargetLesionDialog/nonTargetLesionDialog.js', 'client'); - api.addFiles('components/studyDateList/studyDateList.html', 'client'); - api.addFiles('components/studyDateList/studyDateList.styl', 'client'); - api.addFiles('components/studyDateList/studyDateList.js', 'client'); + api.addFiles('client/components/studyDateList/studyDateList.html', 'client'); + api.addFiles('client/components/studyDateList/studyDateList.styl', 'client'); + api.addFiles('client/components/studyDateList/studyDateList.js', 'client'); - api.addFiles('components/timepointTextDialog/timepointTextDialog.html', 'client'); - api.addFiles('components/timepointTextDialog/timepointTextDialog.styl', 'client'); + api.addFiles('client/components/timepointTextDialog/timepointTextDialog.html', 'client'); + api.addFiles('client/components/timepointTextDialog/timepointTextDialog.styl', 'client'); // Server functions api.addFiles('server/collections.js', 'server'); @@ -57,7 +60,6 @@ Package.onUse(function (api) { // Both client and server functions api.addFiles('both/collections.js', ['client', 'server']); - // Library functions api.addFiles('lib/uuid.js', 'client'); api.addFiles('lib/resizeViewportElements.js', 'client'); @@ -66,7 +68,14 @@ Package.onUse(function (api) { // Export lesionTable function for activate measurements api.export('activateLesion','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('Timepoints', ['client', 'server']); }); \ No newline at end of file diff --git a/Packages/viewerbase/components/viewer/imageViewerViewports/imageViewerViewports.js b/Packages/viewerbase/components/viewer/imageViewerViewports/imageViewerViewports.js index 41c333fde..96ce8ae14 100644 --- a/Packages/viewerbase/components/viewer/imageViewerViewports/imageViewerViewports.js +++ b/Packages/viewerbase/components/viewer/imageViewerViewports/imageViewerViewports.js @@ -121,7 +121,7 @@ var savedSeriesData, savedViewportColumns; Template.imageViewerViewports.events({ - 'dblclick .imageViewerViewport': function(e) { + 'CornerstoneMouseDoubleClick .imageViewerViewport': function(e) { var container = $(".viewerMain").get(0); var data; var contentId = this.contentId || $("#viewer").parents(".tab-pane.active").attr('id'); @@ -140,7 +140,7 @@ Template.imageViewerViewports.events({ data = { viewportRows: ViewerData[contentId].viewportRows, - viewportColumns: ViewerData[contentId].viewportColumns, + viewportColumns: ViewerData[contentId].viewportColumns }; // Render the imageViewerViewports template with these settings @@ -181,7 +181,6 @@ Template.imageViewerViewports.events({ // Add the 'zoomed' class to the lone remaining viewport $('.imageViewerViewport').eq(0).addClass('zoomed'); - } } }); \ No newline at end of file diff --git a/Packages/viewerbase/log.js b/Packages/viewerbase/log.js index bb7ba9220..e188235f2 100644 --- a/Packages/viewerbase/log.js +++ b/Packages/viewerbase/log.js @@ -1,3 +1,3 @@ // Create package logger using loglevel // https://atmospherejs.com/spacejamio/loglevel -log = loglevel.createPackageLogger('viewerbase', defaultLevel = 'info'); \ No newline at end of file +log = loglevel.createPackageLogger('viewerbase', defaultLevel = 'warn'); \ No newline at end of file diff --git a/config/localhostOrthanc.json b/config/localhostOrthanc.json index 0ded25ff0..0097b2f56 100644 --- a/config/localhostOrthanc.json +++ b/config/localhostOrthanc.json @@ -4,7 +4,7 @@ { "name": "Orthanc", "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", "wadoRoot": "http://localhost:8042/dicom-web", "qidoSupportsIncludeField": false, diff --git a/etc/OrthancProxy.js b/etc/OrthancProxy.js new file mode 100644 index 000000000..be7c16053 --- /dev/null +++ b/etc/OrthancProxy.js @@ -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); +});