PWV-15: Creating routing branch

This commit is contained in:
Bruno Alves de Faria 2017-03-02 20:59:55 -03:00
parent e618e32341
commit efb4ca23b5
24 changed files with 158 additions and 437 deletions

View File

@ -2,7 +2,6 @@
{{#if and Template.subscriptionsReady dataSourcesReady}} {{#if and Template.subscriptionsReady dataSourcesReady}}
<div class="viewerDialogs"> <div class="viewerDialogs">
{{>confirmDeleteDialog}} {{>confirmDeleteDialog}}
{{>measurementLocationDialog (clone this)}}
{{>measurementTableHUD (clone this)}} {{>measurementTableHUD (clone this)}}
{{>cineDialog}} {{>cineDialog}}
</div> </div>

View File

@ -1,5 +1,6 @@
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { Tracker } from 'meteor/tracker';
import { Session } from 'meteor/session'; import { Session } from 'meteor/session';
import { ReactiveDict } from 'meteor/reactive-dict'; import { ReactiveDict } from 'meteor/reactive-dict';
import { _ } from 'meteor/underscore'; import { _ } from 'meteor/underscore';
@ -24,6 +25,9 @@ Meteor.startup(() => {
// Metadata configuration // Metadata configuration
const metadataProvider = OHIF.viewer.metadataProvider; const metadataProvider = OHIF.viewer.metadataProvider;
cornerstoneTools.metaData.addProvider(metadataProvider.getProvider()); cornerstoneTools.metaData.addProvider(metadataProvider.getProvider());
// Target tools configuration
OHIF.lesiontracker.configureTargetToolsHandles();
}); });
Template.viewer.onCreated(() => { Template.viewer.onCreated(() => {
@ -35,6 +39,20 @@ Template.viewer.onCreated(() => {
const instance = Template.instance(); const instance = Template.instance();
const { TimepointApi, MeasurementApi, ConformanceCriteria } = OHIF.measurements;
const currentTimepointId = instance.data.currentTimepointId;
const timepointApi = new TimepointApi(currentTimepointId);
const measurementApi = new MeasurementApi(timepointApi);
const conformanceCriteria = new ConformanceCriteria(measurementApi, timepointApi);
const apis = {
timepointApi,
measurementApi,
conformanceCriteria
};
Object.assign(OHIF.viewer, apis);
Object.assign(instance.data, apis);
ValidationErrors.remove({}); ValidationErrors.remove({});
instance.data.state = new ReactiveDict(); instance.data.state = new ReactiveDict();
@ -102,20 +120,15 @@ Template.viewer.onCreated(() => {
OHIF.viewer.StudyMetadataList.insert(studyMetadata); OHIF.viewer.StudyMetadataList.insert(studyMetadata);
}); });
instance.data.timepointApi = new OHIF.measurements.TimepointApi(instance.data.currentTimepointId);
// TODO: Find a better way to pass this to the ViewportOverlay
OHIF.viewer.timepointApi = instance.data.timepointApi;
const patientId = instance.data.studies[0].patientId; const patientId = instance.data.studies[0].patientId;
// LT-382: Preventing HP to keep identifying studies in timepoints that might be removed // LT-382: Preventing HP to keep identifying studies in timepoints that might be removed
instance.data.studies.forEach(study => (delete study.timepointType)); instance.data.studies.forEach(study => (delete study.timepointType));
// TODO: Consider combining the retrieval calls into one? // TODO: Consider combining the retrieval calls into one?
const timepointsPromise = instance.data.timepointApi.retrieveTimepoints(patientId); const timepointsPromise = timepointApi.retrieveTimepoints(patientId);
timepointsPromise.then(() => { timepointsPromise.then(() => {
const timepoints = instance.data.timepointApi.all(); const timepoints = timepointApi.all();
// Set timepointType in studies to be used in hanging protocol engine // Set timepointType in studies to be used in hanging protocol engine
timepoints.forEach(timepoint => { timepoints.forEach(timepoint => {
@ -135,21 +148,19 @@ Template.viewer.onCreated(() => {
Session.set('TimepointsReady', true); Session.set('TimepointsReady', true);
const timepointIds = timepoints.map(t => t.timepointId); const timepointIds = timepoints.map(t => t.timepointId);
instance.data.measurementApi = new OHIF.measurements.MeasurementApi(instance.data.timepointApi);
instance.data.conformanceCriteria = new OHIF.measurements.ConformanceCriteria(instance.data.measurementApi, instance.data.timepointApi);
const measurementsPromise = instance.data.measurementApi.retrieveMeasurements(patientId, timepointIds); const measurementsPromise = measurementApi.retrieveMeasurements(patientId, timepointIds);
measurementsPromise.then(() => { measurementsPromise.then(() => {
Session.set('MeasurementsReady', true); Session.set('MeasurementsReady', true);
instance.data.measurementApi.syncMeasurementsAndToolData(); measurementApi.syncMeasurementsAndToolData();
}); });
}); });
// Provide the necessary data to the Measurement API and Timepoint API // Provide the necessary data to the Measurement API and Timepoint API
const prior = instance.data.timepointApi.prior(); const prior = timepointApi.prior();
if (prior) { if (prior) {
instance.data.measurementApi.priorTimepointId = prior.timepointId; measurementApi.priorTimepointId = prior.timepointId;
} }
if (instance.data.currentTimepointId) { if (instance.data.currentTimepointId) {
@ -177,8 +188,6 @@ Template.viewer.onCreated(() => {
const tools = config.measurementTools[0].childTools; const tools = config.measurementTools[0].childTools;
const firstTool = tools[Object.keys(tools)[0]]; const firstTool = tools[Object.keys(tools)[0]];
const measurementTypeId = firstTool.id; const measurementTypeId = firstTool.id;
const measurementApi = instance.data.measurementApi;
const timepointApi = instance.data.timepointApi;
const collection = measurementApi.tools[measurementTypeId]; const collection = measurementApi.tools[measurementTypeId];
const sorting = { const sorting = {
@ -230,44 +239,45 @@ const setActiveToolAndSidebar = () => {
const { studies, currentTimepointId, measurementApi, timepointIds } = instance.data; const { studies, currentTimepointId, measurementApi, timepointIds } = instance.data;
// Default actions for Associated Studies // Default actions for Associated Studies
if(currentTimepointId) { if (currentTimepointId) {
// Follow-up studies: same as the first measurement in the table // Follow-up studies: same as the first measurement in the table
// Baseline studies: target-tool // Baseline studies: target-tool
if(studies[0]) { if (studies[0]) {
let activeTool; let activeTool;
// In follow-ups, get the baseline timepointId // In follow-ups, get the baseline timepointId
const timepointId = timepointIds.find(id => id !== currentTimepointId); const timepointId = timepointIds.find(id => id !== currentTimepointId);
// Follow-up studies // Follow-up studies
if(studies[0].timepointType === 'followup' && timepointId) { if (studies[0].timepointType === 'followup' && timepointId) {
const measurementTools = OHIF.measurements.MeasurementApi.getConfiguration().measurementTools; const measurementTools = OHIF.measurements.MeasurementApi.getConfiguration().measurementTools;
// Create list of measurement tools // Create list of measurement tools
const measurementTypes = measurementTools.map( const measurementTypes = measurementTools.map(
tool => { tool => {
const { id, cornerstoneToolType } = tool; const { id, cornerstoneToolType } = tool;
return { return {
id, id,
cornerstoneToolType cornerstoneToolType
} };
} }
); );
// Iterate over each measurement tool to find the first baseline // Iterate over each measurement tool to find the first baseline
// measurement. If so, stops the loop and prevent fetching from all // measurement. If so, stops the loop and prevent fetching from all
// collections // collections
measurementTypes.every(({id, cornerstoneToolType}) => { measurementTypes.every(({ id, cornerstoneToolType }) => {
// Get measurement // Get measurement
if(measurementApi[id]) { if (measurementApi[id]) {
const measurement = measurementApi[id].findOne({ timepointId }); const measurement = measurementApi[id].findOne({ timepointId });
// Found a measurement, save tool and stop loop // Found a measurement, save tool and stop loop
if(measurement) { if (measurement) {
activeTool = cornerstoneToolType; activeTool = cornerstoneToolType;
return false; return false;
} }
} }
return true; return true;
}); });
} }
@ -276,14 +286,14 @@ const setActiveToolAndSidebar = () => {
OHIF.viewerbase.toolManager.setActiveTool(activeTool || 'bidirectional'); OHIF.viewerbase.toolManager.setActiveTool(activeTool || 'bidirectional');
} }
// Toggle Measurement Table // Toggle Measurement Table
if(instance.data.state) { if (instance.data.state) {
instance.data.state.set('rightSidebar', 'measurements'); instance.data.state.set('rightSidebar', 'measurements');
} }
} }
// Hide as default for single study // Hide as default for single study
else { else {
if(instance.data.state) { if (instance.data.state) {
instance.data.state.set('rightSidebar', null); instance.data.state.set('rightSidebar', null);
} }
} }

View File

@ -7,7 +7,3 @@ import './optionsModal/optionsModal.js';
import './optionsModal/recistDescription/recistDescription.html'; import './optionsModal/recistDescription/recistDescription.html';
import './optionsModal/irRCDescription/irRCDescription.html'; import './optionsModal/irRCDescription/irRCDescription.html';
import './measurementLocationDialog/measurementLocationDialog.html';
import './measurementLocationDialog/measurementLocationDialog.js';
import './measurementLocationDialog/measurementLocationDialog.styl';

View File

@ -1,38 +0,0 @@
<template name="measurementLocationDialog">
<div id="measurementLocationDialog" class="dialog-animated" tabindex="0">
<div class="dialogHeader">
<h4>Select Location</h4>
</div>
<div class="dialogContent">
<div class="measurementLocation">
<label>Location</label>
<select class="selectMeasurementLocation">
<option value="-1"></option>
{{ #each measurementLocations}}
<option value='{{_id}}'>{{location}}</option>
{{ /each}}
</select>
</div>
</div>
</div>
<div id="measurementLocationRelabelDialog" class="dialog-animated" tabindex="0">
<div class="dialogHeader">
<h4>Change Location</h4>
</div>
<a></a>
<div class="dialogContent">
<div class="measurementLocation">
<label>Location</label>
<select class="selectMeasurementLocation">
<option value="-1"></option>
{{ #each measurementLocations}}
<option value='{{_id}}' selected={{selected}}>{{location}}</option>
{{ /each}}
</select>
</div>
<button id="removeLesion" class="btn btn-link">Remove</button>
<button id="convertToNonTarget" class="btn btn-link">Convert to Non-Target</button>
</div>
</div>
</template>

View File

@ -1,91 +0,0 @@
// Note: This component is not in use, but the functions below are still being used. This
// is in the process of being moved into another location
import { OHIF } from 'meteor/ohif:core';
Template.measurementLocationDialog.onCreated(() => {
const instance = Template.instance();
const measurementApi = instance.data.measurementApi;
const toggleLabel = (measurementData, eventData, doneCallback) => {
delete measurementData.isCreating;
if (OHIF.lesiontracker.removeMeasurementIfInvalid(measurementData, eventData)) {
return;
}
const getHandlePosition = key => _.pick(measurementData.handles[key], ['x', 'y']);
const start = getHandlePosition('start');
const end = getHandlePosition('end');
const getDirection = axis => start[axis] < end[axis] ? 1 : -1;
const position = OHIF.cornerstone.pixelToPage(eventData.element, end);
OHIF.measurements.toggleLabelButton({
instance,
measurement: measurementData,
element: eventData.element,
measurementApi,
position: position,
direction: {
x: getDirection('x'),
y: getDirection('y')
}
});
};
const callbackConfig = {
// TODO: Check the position for these, the Add Label button position seems very awkward
getMeasurementLocationCallback: toggleLabel,
changeMeasurementLocationCallback: toggleLabel,
};
// TODO: Reconcile this with the configuration in toolManager
// it would be better to have this all in one place.
const bidirectionalConfig = cornerstoneTools.bidirectional.getConfiguration();
const config = {
...bidirectionalConfig,
...callbackConfig
};
cornerstoneTools.bidirectional.setConfiguration(config);
// Set CR-Tool, UN-Tool, EX-Tool configurations
cornerstoneTools.targetCR.setConfiguration(config);
cornerstoneTools.targetUN.setConfiguration(config);
cornerstoneTools.targetEX.setConfiguration(config);
});
// Note: None of these events work anymore
Template.measurementLocationDialog.events({
'click #removeMeasurement'() {
const measurementData = Template.measurementLocationDialog.measurementData;
const doneCallback = Template.measurementLocationDialog.doneCallback;
const dialog = Template.measurementLocationDialog.dialog;
const options = {
keyPressAllowed: false,
title: 'Remove measurement?',
text: 'Are you sure you would like to remove the entire measurement?'
};
showConfirmDialog(function() {
if (doneCallback && typeof doneCallback === 'function') {
const deleteTool = true;
doneCallback(measurementData, deleteTool);
}
}, options);
closeHandler(dialog);
},
'click #convertToNonTarget'() {
const measurementData = Template.measurementLocationDialog.measurementData;
const dialog = Template.measurementLocationDialog.dialog;
const instance = Template.instance();
const measurementApi = instance.data.measurementApi;
OHIF.measurementTracker.convertToNonTarget(measurementApi, measurementData);
closeHandler(dialog);
}
});

View File

@ -1,35 +0,0 @@
#measurementLocationDialog, #measurementLocationRelabelDialog
display: none
position: absolute
top: 0
bottom: 0
left: 0
right: 0
z-index: 100
width: 300px
height: 130px
border-radius: 5px
padding: 10px 20px 10px 20px
background-color: rgba(255,255,255,1)
outline: none
#closeLesionPopup
outline: none
border: none
background-color: transparent
#selectMeasurementLocation
margin-top: 5px
.dialogContent
margin-bottom: 10px
#removeLesion
outline: none
text-decoration: none
#measurementLocationDialog
height: 110px
#measurementLocationRelabelDialog
height: 125px

View File

@ -1,4 +1,3 @@
import { Template } from 'meteor/templating';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
// Define the Trial Criteria Structure // Define the Trial Criteria Structure
@ -21,9 +20,9 @@ OHIF.lesiontracker.TrialCriteriaConstraints = {
* - Time Point Measurement Total = Sum of long axis measurements for extranodal target lesion + short axis measurements for nodal lesions * - Time Point Measurement Total = Sum of long axis measurements for extranodal target lesion + short axis measurements for nodal lesions
*/ */
function RECIST(image) { function RECIST(image) {
var acquisitionSliceThickness; let acquisitionSliceThickness;
var isChestXray; let isChestXray;
if (image) { if (image) {
acquisitionSliceThickness = image.acquisitionSliceThickness; acquisitionSliceThickness = image.acquisitionSliceThickness;
@ -32,7 +31,7 @@ function RECIST(image) {
} }
// Define the RECIST 1.1 structure // Define the RECIST 1.1 structure
var criteria = { const criteria = {
baseline: { baseline: {
target: {}, target: {},
nonTarget: {}, nonTarget: {},
@ -160,13 +159,13 @@ function RECIST(image) {
* - Target lesions must have measurements (cannot be assessed as CR, UN/NE, EX) * - Target lesions must have measurements (cannot be assessed as CR, UN/NE, EX)
*/ */
function irRC(image) { function irRC(image) {
var acquisitionSliceThickness; let acquisitionSliceThickness;
if (image) { if (image) {
acquisitionSliceThickness = image.acquisitionSliceThickness; acquisitionSliceThickness = image.acquisitionSliceThickness;
} }
// Define the irRC structure // Define the irRC structure
var criteria = { const criteria = {
baseline: { baseline: {
target: {}, target: {},
nonTarget: {} nonTarget: {}
@ -372,7 +371,7 @@ OHIF.lesiontracker.getTrialCriteriaConstraints = (criteriaTypes, imageId) => {
} }
// Find the related Timepoint document // Find the related Timepoint document
const timepointApi = Template.instance().timepointApi; const { timepointApi } = OHIF.viewer;
if (!timepointApi) { if (!timepointApi) {
return; return;
} }

View File

@ -0,0 +1,47 @@
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core';
OHIF.lesiontracker.configureTargetToolsHandles = () => {
const toggleLabel = (measurementData, eventData, doneCallback) => {
delete measurementData.isCreating;
if (OHIF.lesiontracker.removeMeasurementIfInvalid(measurementData, eventData)) {
return;
}
const getHandlePosition = key => _.pick(measurementData.handles[key], ['x', 'y']);
const start = getHandlePosition('start');
const end = getHandlePosition('end');
const getDirection = axis => start[axis] < end[axis] ? 1 : -1;
const position = OHIF.cornerstone.pixelToPage(eventData.element, end);
OHIF.measurements.toggleLabelButton({
measurement: measurementData,
element: eventData.element,
measurementApi: OHIF.viewer.measurementApi,
position: position,
direction: {
x: getDirection('x'),
y: getDirection('y')
}
});
};
const callbackConfig = {
// TODO: Check the position for these, the Add Label button position seems very awkward
getMeasurementLocationCallback: toggleLabel,
changeMeasurementLocationCallback: toggleLabel,
};
// TODO: Reconcile this with the configuration in toolManager
// it would be better to have this all in one place.
const bidirectionalConfig = cornerstoneTools.bidirectional.getConfiguration();
const config = Object.assign({}, bidirectionalConfig, callbackConfig);
cornerstoneTools.bidirectional.setConfiguration(config);
// Set CR-Tool, UN-Tool, EX-Tool configurations
cornerstoneTools.targetCR.setConfiguration(config);
cornerstoneTools.targetUN.setConfiguration(config);
cornerstoneTools.targetEX.setConfiguration(config);
};

View File

@ -1,72 +0,0 @@
import { OHIF } from 'meteor/ohif:core';
var responseTypes = {
targetCR: 'CR',
targetUN: 'UN',
targetEX: 'EX'
};
convertNonTarget = function(measurementApi, measurementData, newTooltype) {
if (measurementData.toolType !== 'nonTarget') {
return;
}
var measurement = Measurements.findOne(measurementData.id);
var timepoint = Timepoints.findOne({
timepointId: measurementData.timepointId
});
if (timepoint && timepoint.timepointType !== 'followup') {
OHIF.log.warn('Not a followup');
return;
}
// Next, update the measurementData and add it to the new tool type
var newMeasurement = {
id: 'notready',
lesionNumber: measurementApi.getNewLesionNumber(measurementData.timepointId, false),
visible: true,
active: true,
imageId: measurementData.imageId,
seriesInstanceUid: measurementData.seriesInstanceUid,
studyInstanceUid: measurementData.studyInstanceUid,
patientId: measurementData.patientId,
isTarget: false,
toolType: newTooltype
};
newMeasurement.handles = measurementData.handles;
if (responseTypes[newTooltype]) {
newMeasurement.response = responseTypes[newTooltype];
}
// Adds lesion data to timepoints array
measurementApi.updateLesionData(newMeasurement);
// Set the new Measurement to have the same location as the old one
if (measurement.location && measurement.locationId) {
var existingMeasurement = Measurements.findOne({
lesionNumber: newMeasurement.lesionNumber,
isTarget: newMeasurement.isTarget
});
if (!existingMeasurement) {
return;
}
Measurements.update(existingMeasurement._id, {
$set: {
location: measurement.location,
locationId: measurement.locationId
}
});
}
if (measurement) {
// Remove the timepointData from this Measurement and update it
// in the database, if it is already in the database
OHIF.lesiontracker.clearMeasurementTimepointData(measurement._id, measurementData.timepointId);
}
};

View File

@ -1,86 +0,0 @@
import { OHIF } from 'meteor/ohif:core';
OHIF.lesiontracker.convertToNonTarget = (measurementApi, measurementData) => {
if (measurementData.isTarget === false) {
return;
}
const measurement = Measurements.findOne(measurementData.id);
const timepoint = Timepoints.findOne({
timepointId: measurementData.timepointId
});
// Next, update the measurementData and add it to the new tool type
const toolType = 'nonTarget';
const newMeasurement = {
id: 'notready',
lesionNumber: LesionManager.getNewLesionNumber(measurementData.timepointId, false),
visible: true,
active: true,
imageId: measurementData.imageId,
seriesInstanceUid: measurementData.seriesInstanceUid,
studyInstanceUid: measurementData.studyInstanceUid,
patientId: measurementData.patientId,
isTarget: false,
toolType: toolType
};
if (timepoint && timepoint.timepointType === 'baseline') {
newMeasurement.response = 'Present';
} else {
newMeasurement.response = '';
}
newMeasurement.handles = {
start: {
x: (measurementData.handles.start.x + measurementData.handles.end.x) / 2,
y: (measurementData.handles.start.y + measurementData.handles.end.y) / 2,
highlight: true,
active: false
},
end: {
x: Math.min(measurementData.handles.start.x, measurementData.handles.end.x),
y: Math.min(measurementData.handles.start.y, measurementData.handles.end.y),
highlight: true,
active: false
},
textBox: {
x: measurementData.handles.textBox.x,
y: measurementData.handles.textBox.y,
active: false,
movesIndependently: false,
drawnIndependently: true,
allowedOutsideImage: true,
hasBoundingBox: true
}
};
// Adds lesion data to timepoints array
LesionManager.updateLesionData(newMeasurement);
// Set the new Measurement to have the same location as the old one
if (measurement.location && measurement.locationId) {
var existingMeasurement = Measurements.findOne({
lesionNumber: newMeasurement.lesionNumber,
isTarget: newMeasurement.isTarget
});
if (!existingMeasurement) {
return;
}
Measurements.update(existingMeasurement._id, {
$set: {
location: measurement.location,
locationId: measurement.locationId
}
});
}
if (measurement) {
// Remove the timepointData from this Measurement and update it
// in the database, if it is already in the database
OHIF.lesiontracker.clearMeasurementTimepointData(measurement._id, measurementData.timepointId);
}
};

View File

@ -9,5 +9,4 @@ import './pixelSpacingAutorunCheck.js';
import './removeMeasurementIfInvalid.js'; import './removeMeasurementIfInvalid.js';
import './toggleLesionTrackerTools.js'; import './toggleLesionTrackerTools.js';
import './clearMeasurementTimepointData.js'; import './clearMeasurementTimepointData.js';
import './convertToNonTarget.js'; import './configureTargetToolsHandles.js';
import './convertNonTarget.js';

View File

@ -12,8 +12,6 @@ Template.caseProgress.onCreated(() => {
instance.path = 'viewer.studyViewer.measurements'; instance.path = 'viewer.studyViewer.measurements';
instance.saveData = () => { instance.saveData = () => {
const api = instance.data.measurementApi;
// Clear signaled unsaved changes... // Clear signaled unsaved changes...
const successHandler = () => { const successHandler = () => {
OHIF.ui.unsavedChanges.clear(`${instance.path}.*`); OHIF.ui.unsavedChanges.clear(`${instance.path}.*`);
@ -22,7 +20,7 @@ Template.caseProgress.onCreated(() => {
// Display the error messages // Display the error messages
const errorHandler = data => OHIF.ui.showDialog('dialogInfo', data); const errorHandler = data => OHIF.ui.showDialog('dialogInfo', data);
const promise = api.storeMeasurements(); const promise = instance.data.measurementApi.storeMeasurements();
promise.then(successHandler).catch(errorHandler); promise.then(successHandler).catch(errorHandler);
OHIF.ui.showDialog('dialogLoading', { OHIF.ui.showDialog('dialogLoading', {
promise, promise,
@ -51,16 +49,17 @@ Template.caseProgress.onDestroyed(() => {
Template.caseProgress.onRendered(() => { Template.caseProgress.onRendered(() => {
const instance = Template.instance(); const instance = Template.instance();
const { timepointApi, measurementApi } = instance.data;
// Stop here if we have no current timepoint ID (and therefore no defined timepointAPI) // Stop here if we have no current timepoint ID (and therefore no defined timepointAPI)
if (!instance.data.timepointApi) { if (!timepointApi) {
instance.progressPercent.set(100); instance.progressPercent.set(100);
return; return;
} }
// Get the current timepoint // Get the current timepoint
const current = instance.data.timepointApi.current(); const current = timepointApi.current();
const prior = instance.data.timepointApi.prior(); const prior = timepointApi.prior();
if (!current || !prior || !current.timepointId) { if (!current || !prior || !current.timepointId) {
instance.progressPercent.set(100); instance.progressPercent.set(100);
return; return;
@ -72,7 +71,6 @@ Template.caseProgress.onRendered(() => {
// follow-up. Note that this is done outside of the reactive function // follow-up. Note that this is done outside of the reactive function
// below so that new lesions don't change the initial target count. // below so that new lesions don't change the initial target count.
const api = instance.data.measurementApi;
const config = OHIF.measurements.MeasurementApi.getConfiguration(); const config = OHIF.measurements.MeasurementApi.getConfiguration();
const toolGroups = config.measurementTools; const toolGroups = config.measurementTools;
@ -95,7 +93,7 @@ Template.caseProgress.onRendered(() => {
let count = 0; let count = 0;
toolGroups.forEach(toolGroup => { toolGroups.forEach(toolGroup => {
count += api.fetch(toolGroup.id, filter).length; count += measurementApi.fetch(toolGroup.id, filter).length;
}); });
return count; return count;
@ -108,8 +106,8 @@ Template.caseProgress.onRendered(() => {
let totalRemaining = 0; let totalRemaining = 0;
toolGroups.forEach(toolGroup => { toolGroups.forEach(toolGroup => {
const toolGroupId = toolGroup.id; const toolGroupId = toolGroup.id;
const numCurrent = api.fetch(toolGroupId, currentFilter).length; const numCurrent = measurementApi.fetch(toolGroupId, currentFilter).length;
const numPrior = api.fetch(toolGroupId, priorFilter).length; const numPrior = measurementApi.fetch(toolGroupId, priorFilter).length;
const remaining = Math.max(numPrior - numCurrent, 0); const remaining = Math.max(numPrior - numCurrent, 0);
totalRemaining += remaining; totalRemaining += remaining;
}); });
@ -125,7 +123,7 @@ Template.caseProgress.onRendered(() => {
// Setup a reactive function to update the progress whenever // Setup a reactive function to update the progress whenever
// a measurement is made // a measurement is made
instance.autorun(() => { instance.autorun(() => {
api.changeObserver.depend(); measurementApi.changeObserver.depend();
// Obtain the number of Measurements for which the current Timepoint has // Obtain the number of Measurements for which the current Timepoint has
// no Measurement data // no Measurement data
const totalMeasurements = getNumMeasurementsAtTimepoint(prior.timepointId); const totalMeasurements = getNumMeasurementsAtTimepoint(prior.timepointId);

View File

@ -14,13 +14,14 @@ Template.measurementTable.onCreated(() => {
// Get the current table layout // Get the current table layout
const tableLayout = instance.data.measurementTableLayout.get(); const tableLayout = instance.data.measurementTableLayout.get();
const timepointApi = instance.data.timepointApi;
let timepoints; let timepoints;
if (!instance.data.timepointApi) { if (!timepointApi) {
timepoints = []; timepoints = [];
} else if (tableLayout === 'key') { } else if (tableLayout === 'key') {
timepoints = instance.data.timepointApi.key(); timepoints = timepointApi.key();
} else { } else {
timepoints = instance.data.timepointApi.currentAndPrior(); timepoints = timepointApi.currentAndPrior();
} }
// Return key timepoints // Return key timepoints

View File

@ -1,9 +1,14 @@
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
Template.measurementTableHUD.onCreated(() => { Template.measurementTableHUD.onCreated(() => {
const instance = Template.instance(); const instance = Template.instance();
const timepointApi = instance.data.timepointApi;
instance.isRemoved = true; instance.isRemoved = true;
if (instance.data.timepointApi) { if (timepointApi) {
instance.data.timepoints = new ReactiveVar(instance.data.timepointApi.currentAndPrior()); instance.data.timepoints = new ReactiveVar(timepointApi.currentAndPrior());
} }
}); });
@ -37,6 +42,7 @@ Template.measurementTableHUD.helpers({
return instance.isRemoved !== true ? 'dialog-animated dialog-closed' : 'hidden'; return instance.isRemoved !== true ? 'dialog-animated dialog-closed' : 'hidden';
}, },
toolbarButtons() { toolbarButtons() {
let buttonData = []; let buttonData = [];

View File

@ -52,7 +52,6 @@ Template.measurementTableRow.events({
// Show the measure flow for targets // Show the measure flow for targets
OHIF.measurements.toggleLabelButton({ OHIF.measurements.toggleLabelButton({
instance,
measurement: entry, measurement: entry,
element: document.body, element: document.body,
measurementApi: instance.data.measurementApi, measurementApi: instance.data.measurementApi,
@ -78,8 +77,7 @@ Template.measurementTableRow.events({
const measurementTypeId = instance.data.rowItem.measurementTypeId; const measurementTypeId = instance.data.rowItem.measurementTypeId;
const measurement = instance.data.rowItem.entries[0]; const measurement = instance.data.rowItem.entries[0];
const measurementNumber = measurement.measurementNumber; const measurementNumber = measurement.measurementNumber;
const measurementApi = instance.data.measurementApi; const { timepointApi, measurementApi } = instance.data;
const timepointApi = instance.data.timepointApi;
// Remove all the measurements with the given type and number // Remove all the measurements with the given type and number
measurementApi.deleteMeasurements(measurementTypeId, { measurementNumber }); measurementApi.deleteMeasurements(measurementTypeId, { measurementNumber });

View File

@ -1,3 +1,5 @@
import { Template } from 'meteor/templating';
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
Template.measurementTableTimepointCell.helpers({ Template.measurementTableTimepointCell.helpers({
@ -15,6 +17,7 @@ Template.measurementTableTimepointCell.helpers({
return rowItem.entries.length > 0; return rowItem.entries.length > 0;
} }
}, },
displayData() { displayData() {
const instance = Template.instance(); const instance = Template.instance();
const rowItem = instance.data.rowItem; const rowItem = instance.data.rowItem;
@ -26,6 +29,7 @@ Template.measurementTableTimepointCell.helpers({
if (dataAtThisTimepoint.length > 1) { if (dataAtThisTimepoint.length > 1) {
throw 'More than one measurement was found at the same timepoint with the same measurement number?'; throw 'More than one measurement was found at the same timepoint with the same measurement number?';
} }
data = dataAtThisTimepoint[0]; data = dataAtThisTimepoint[0];
} else { } else {
data = rowItem.entries[0]; data = rowItem.entries[0];
@ -38,29 +42,14 @@ Template.measurementTableTimepointCell.helpers({
const tool = _.findWhere(toolGroup.childTools, { id: data.toolType }); const tool = _.findWhere(toolGroup.childTools, { id: data.toolType });
if (!tool) { if (!tool) {
// TODO: Figure out what is going on here? // TODO: Figure out what is going on here?
console.warn('Something went wrong?'); OHIF.log.warn('Something went wrong?');
} }
const displayFunction = tool.options.measurementTable.displayFunction; const displayFunction = tool.options.measurementTable.displayFunction;
return displayFunction(data); return displayFunction(data);
} }
}); });
function doneCallback(measurementData, deleteTool) {
// If a Lesion or Non-Target is removed via a dialog
// opened by the Lesion Table, we should clear the data for
// the specified Timepoint Cell
if (deleteTool === true) {
OHIF.log.info('Confirm clicked!');
OHIF.lesiontracker.clearMeasurementTimepointData(measurementData.id, measurementData.timepointId);
}
}
// Delete a lesion if Ctrl+D or DELETE is pressed while a lesion is selected
const keys = {
D: 68,
DELETE: 46
};
Template.measurementTableTimepointCell.events({ Template.measurementTableTimepointCell.events({
'click .measurementTableTimepointCell'(event, instance) { 'click .measurementTableTimepointCell'(event, instance) {
if (!instance.data.timepointId) { if (!instance.data.timepointId) {
@ -71,14 +60,18 @@ Template.measurementTableTimepointCell.events({
const timepoints = instance.data.timepoints.get(); const timepoints = instance.data.timepoints.get();
OHIF.measurements.jumpToRowItem(rowItem, timepoints); OHIF.measurements.jumpToRowItem(rowItem, timepoints);
}, },
'keydown .measurementTableTimepointCell'(event, instance) { 'keydown .measurementTableTimepointCell'(event, instance) {
// Delete a lesion if Ctrl+D or DELETE is pressed while a lesion is selected
const keys = {
D: 68,
DELETE: 46
};
const keyCode = event.which; const keyCode = event.which;
if (keyCode === keys.DELETE || keyCode === keys.BACKSPACE || (keyCode === keys.D && event.ctrlKey === true)) { if (keyCode === keys.DELETE || keyCode === keys.BACKSPACE || (keyCode === keys.D && event.ctrlKey === true)) {
const currentMeasurement = Template.parentData(1).rowItem; const timepointId = instance.data.timepointId;
const timepointId = this.timepointId;
const dialogSettings = { const dialogSettings = {
title: 'Delete measurements', title: 'Delete measurements',
message: 'Are you sure you want to delete this measurement?' message: 'Are you sure you want to delete this measurement?'
@ -88,8 +81,7 @@ Template.measurementTableTimepointCell.events({
const measurementTypeId = instance.data.rowItem.measurementTypeId; const measurementTypeId = instance.data.rowItem.measurementTypeId;
const measurement = instance.data.rowItem.entries[0]; const measurement = instance.data.rowItem.entries[0];
const measurementNumber = measurement.measurementNumber; const measurementNumber = measurement.measurementNumber;
const measurementApi = instance.data.measurementApi; const { timepointApi, measurementApi } = instance.data;
const timepointApi = instance.data.timepointApi;
// Remove all the measurements with the given type and number // Remove all the measurements with the given type and number
measurementApi.deleteMeasurements(measurementTypeId, { measurementApi.deleteMeasurements(measurementTypeId, {

View File

@ -1,7 +1,7 @@
<template name="measurementTableTimepointHeader"> <template name="measurementTableTimepointHeader">
<div class="measurementTableTimepointHeader"> <div class="measurementTableTimepointHeader">
<div class="timepointName"> <div class="timepointName">
{{timepointName}} {{timepointName this}}
</div> </div>
<div class="timepointDate"> <div class="timepointDate">
{{formatDA latestDate "DD-MMM-YY"}} {{formatDA latestDate "DD-MMM-YY"}}

View File

@ -1,8 +1,7 @@
import { Template } from 'meteor/templating';
Template.measurementTableTimepointHeader.helpers({ Template.measurementTableTimepointHeader.helpers({
'timepointName': function() { timepointName(timepoint) {
const timepoint = this; return Template.instance().data.timepointApi.name(timepoint);
const instance = Template.instance();
const timepointApi = instance.data.timepointApi;
return timepointApi.name(timepoint);
} }
}); });

View File

@ -1,5 +1,6 @@
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { Tracker } from 'meteor/tracker'; import { Tracker } from 'meteor/tracker';
import { ReactiveVar } from 'meteor/reactive-var';
import { _ } from 'meteor/underscore'; import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
@ -31,7 +32,7 @@ Template.measurementTableView.helpers({
if (!groups) { if (!groups) {
return false; return false;
} }
const group = _.find(groups, item => item.toolGroup.id === toolGroupId); const group = _.find(groups, item => item.toolGroup.id === toolGroupId);
return group && !!group.measurementRows.length; return group && !!group.measurementRows.length;
}, },
@ -57,10 +58,8 @@ Template.measurementTableView.helpers({
}, },
newMeasurements(toolGroup) { newMeasurements(toolGroup) {
const instance = Template.instance(); const { measurementApi, timepointApi } = Template.instance().data;
const measurementApi = instance.data.measurementApi; const current = timepointApi.current();
const timepointApi = instance.data.timepointApi;
const current = instance.data.timepointApi.current();
const baseline = timepointApi.baseline(); const baseline = timepointApi.baseline();
if (!measurementApi || !timepointApi || !current || !baseline) return; if (!measurementApi || !timepointApi || !current || !baseline) return;

View File

@ -6,8 +6,8 @@ import { OHIF } from 'meteor/ohif:core';
class MeasurementHandlers { class MeasurementHandlers {
static onAdded(e, instance, eventData) { static onAdded(e, instance, eventData) {
const { measurementApi } = instance.data;
const measurementData = eventData.measurementData; const measurementData = eventData.measurementData;
const measurementApi = instance.data.measurementApi;
const Collection = measurementApi.tools[eventData.toolType]; const Collection = measurementApi.tools[eventData.toolType];
// Stop here if the tool data shall not be stored (e.g. temp tools) // Stop here if the tool data shall not be stored (e.g. temp tools)
@ -74,8 +74,8 @@ class MeasurementHandlers {
} }
static onModified(e, instance, eventData) { static onModified(e, instance, eventData) {
const { measurementApi } = instance.data;
const measurementData = eventData.measurementData; const measurementData = eventData.measurementData;
const measurementApi = instance.data.measurementApi;
const Collection = measurementApi.tools[eventData.toolType]; const Collection = measurementApi.tools[eventData.toolType];
// Stop here if the tool data shall not be stored (e.g. temp tools) // Stop here if the tool data shall not be stored (e.g. temp tools)
@ -119,8 +119,7 @@ class MeasurementHandlers {
OHIF.log.info('CornerstoneToolsMeasurementRemoved'); OHIF.log.info('CornerstoneToolsMeasurementRemoved');
const measurementData = eventData.measurementData; const measurementData = eventData.measurementData;
const measurementNumber = measurementData.measurementNumber; const measurementNumber = measurementData.measurementNumber;
const measurementApi = instance.data.measurementApi; const { measurementApi, timepointApi } = instance.data;
const timepointApi = instance.data.timepointApi;
const collection = measurementApi.tools[eventData.toolType]; const collection = measurementApi.tools[eventData.toolType];
const measurementTypeId = measurementApi.toolsGroupsMap[measurementData.toolType]; const measurementTypeId = measurementApi.toolsGroupsMap[measurementData.toolType];
const measurement = collection.findOne(measurementData._id); const measurement = collection.findOne(measurementData._id);

View File

@ -1,6 +1,6 @@
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Viewerbase } from 'meteor/ohif:viewerbase'; import { Viewerbase } from 'meteor/ohif:viewerbase';
import { OHIF } from 'meteor/ohif:core';
const { InstanceMetadata, StudySummary } = Viewerbase.metadata; const { InstanceMetadata, StudySummary } = Viewerbase.metadata;
@ -11,9 +11,9 @@ const { InstanceMetadata, StudySummary } = Viewerbase.metadata;
* @return {String|undefined} Timepoint type if found or undefined if not found or any error/missing information * @return {String|undefined} Timepoint type if found or undefined if not found or any error/missing information
*/ */
const getTimepointType = study => { const getTimepointType = study => {
const timepointApi = OHIF.viewer.timepointApi; const { timepointApi } = OHIF.viewer;
if (!timepointApi || !(study instanceof InstanceMetadata || study instanceof StudySummary) ) { if (!timepointApi || !(study instanceof InstanceMetadata || study instanceof StudySummary)) {
return; return;
} }

View File

@ -6,17 +6,18 @@ import { OHIF } from 'meteor/ohif:core';
OHIF.measurements.toggleLabelButton = options => { OHIF.measurements.toggleLabelButton = options => {
const toolType = options.measurement.toolType; const toolType = options.measurement.toolType;
const measurementId = options.measurement._id; const measurementId = options.measurement._id;
let buttonView = null;
const removeButtonView = () => { const removeButtonView = () => {
if (!options.instance.buttonView) { if (!buttonView) {
return; return;
} }
Blaze.remove(options.instance.buttonView); Blaze.remove(buttonView);
options.instance.buttonView = null; buttonView = null;
}; };
if (options.instance.buttonView) { if (buttonView) {
removeButtonView(); removeButtonView();
} }
@ -53,6 +54,5 @@ OHIF.measurements.toggleLabelButton = options => {
options.measurement.description = description; options.measurement.description = description;
} }
}; };
const view = Blaze.renderWithData(Template.measureFlow, data, options.element); buttonView = Blaze.renderWithData(Template.measureFlow, data, options.element);
options.instance.buttonView = view;
}; };

View File

@ -146,22 +146,23 @@ Template.studyTimepointBrowser.helpers({
// Get the current study // Get the current study
const currentStudy = instance.getCurrentStudy(); const currentStudy = instance.getCurrentStudy();
// Declare the timepoints // Declare the timepoints
const { timepointApi } = instance.data;
let timepoints; let timepoints;
if (currentStudy && !instance.showAdditionalTimepoints.get()) { if (currentStudy && !instance.showAdditionalTimepoints.get()) {
// Show only the current study's timepoint // Show only the current study's timepoint
timepoints = instance.data.timepointApi.study(currentStudy.studyInstanceUid); timepoints = timepointApi.study(currentStudy.studyInstanceUid);
} else { } else {
if (!instance.data.timepointApi) { if (!timepointApi) {
// If there is no timepoint API defined whatsoever, this means that there is no // If there is no timepoint API defined whatsoever, this means that there is no
// current timepoint ID, so we can just display all of the currently loaded studies // current timepoint ID, so we can just display all of the currently loaded studies
// in the study sidebar // in the study sidebar
timepoints = []; timepoints = [];
} else if (instance.timepointViewType.get() === 'all') { } else if (instance.timepointViewType.get() === 'all') {
// Show all timepoints // Show all timepoints
timepoints = instance.data.timepointApi.all(); timepoints = timepointApi.all();
} else { } else {
// Show only key timepoints // Show only key timepoints
timepoints = instance.data.timepointApi.key(); timepoints = timepointApi.key();
} }
} }
// Returns the timepoints // Returns the timepoints

View File

@ -1,9 +1,9 @@
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating'; import { Template } from 'meteor/templating';
import { Session } from 'meteor/session'; import { Session } from 'meteor/session';
import { Random } from 'meteor/random';
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
// Local Modules // Local Modules
import { toolManager } from '../../../lib/toolManager';
import { unloadHandlers } from '../../../lib/unloadHandlers'; import { unloadHandlers } from '../../../lib/unloadHandlers';
import { hotkeyUtils } from '../../../lib/hotkeyUtils'; import { hotkeyUtils } from '../../../lib/hotkeyUtils';
import { ResizeViewportManager } from '../../../lib/classes/ResizeViewportManager'; import { ResizeViewportManager } from '../../../lib/classes/ResizeViewportManager';
@ -13,7 +13,7 @@ import { StudyPrefetcher } from '../../../lib/classes/StudyPrefetcher';
Meteor.startup(() => { Meteor.startup(() => {
window.ResizeViewportManager = window.ResizeViewportManager || new ResizeViewportManager(); window.ResizeViewportManager = window.ResizeViewportManager || new ResizeViewportManager();
// Set initial value for OHIFViewerMainRendered // Set initial value for OHIFViewerMainRendered
// session variable. This can used in viewer main template // session variable. This can used in viewer main template
Session.set('OHIFViewerMainRendered', false); Session.set('OHIFViewerMainRendered', false);
}); });
@ -22,7 +22,7 @@ Template.viewerMain.onCreated(() => {
// Attach the Window resize listener // Attach the Window resize listener
// Don't use jQuery here. "window.onresize" will always be null // Don't use jQuery here. "window.onresize" will always be null
// If its necessary, check all the code for window.onresize getter // If its necessary, check all the code for window.onresize getter
// and change it to jQuery._data(window, 'events')['resize']. // and change it to jQuery._data(window, 'events')['resize'].
// Otherwise this function will be probably overrided. // Otherwise this function will be probably overrided.
// See cineDialog instance.setResizeHandler function // See cineDialog instance.setResizeHandler function
window.addEventListener('resize', window.ResizeViewportManager.getResizeHandler()); window.addEventListener('resize', window.ResizeViewportManager.getResizeHandler());
@ -59,7 +59,7 @@ Template.viewerMain.onDestroyed(() => {
OHIF.viewer.updateImageSynchronizer.destroy(); OHIF.viewer.updateImageSynchronizer.destroy();
delete OHIF.viewerbase.layoutManager; delete OHIF.viewerbase.layoutManager;
delete ProtocolEngine; ProtocolEngine = null;
Session.set('OHIFViewerMainRendered', false); Session.set('OHIFViewerMainRendered', false);
}); });