Added Measurements Observe hook to repopulate toolData from database. Refactored lesion tools and lesionTable.
This commit is contained in:
parent
9ad2ccaaaf
commit
c178505d38
@ -69,7 +69,7 @@ Template.viewer.onCreated(function() {
|
||||
}
|
||||
|
||||
var contentId = this.data.contentId;
|
||||
|
||||
|
||||
if (ViewerData[contentId].loadedSeriesData) {
|
||||
log.info('Reloading previous loadedSeriesData');
|
||||
|
||||
@ -78,7 +78,7 @@ Template.viewer.onCreated(function() {
|
||||
} else {
|
||||
log.info('Setting default ViewerData');
|
||||
OHIF.viewer.loadedSeriesData = {};
|
||||
|
||||
|
||||
ViewerData[contentId].loadedSeriesData = OHIF.viewer.loadedSeriesData;
|
||||
|
||||
// Update the viewer data object
|
||||
@ -90,7 +90,6 @@ Template.viewer.onCreated(function() {
|
||||
|
||||
Session.set('activeViewport', ViewerData[contentId].activeViewport || 0);
|
||||
|
||||
|
||||
// Update the ViewerStudies collection with the loaded studies
|
||||
ViewerStudies = new Meteor.Collection(null);
|
||||
this.data.studies.forEach(function(study) {
|
||||
@ -101,7 +100,7 @@ Template.viewer.onCreated(function() {
|
||||
var patientId = this.data.studies[0].patientId;
|
||||
Session.set('patientId', patientId);
|
||||
|
||||
timepointsAdded = false;
|
||||
initialized = false;
|
||||
self.autorun(function() {
|
||||
var patientId = Session.get('patientId');
|
||||
self.subscribe('timepoints', patientId);
|
||||
@ -111,7 +110,7 @@ Template.viewer.onCreated(function() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (timepointsAdded === true) {
|
||||
if (initialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -138,12 +137,65 @@ Template.viewer.onCreated(function() {
|
||||
});
|
||||
});
|
||||
|
||||
timepointsAdded = true;
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info('Measurement added');
|
||||
addMeasurementAsToolData(data);
|
||||
}
|
||||
});
|
||||
|
||||
initialized = true;
|
||||
});
|
||||
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer("CornerstoneNewImage", cornerstoneTools.updateImageSynchronizer);
|
||||
});
|
||||
|
||||
function addMeasurementAsToolData(data) {
|
||||
// Check what toolType we should be adding this to, based on the isTarget value
|
||||
// of the stored Measurement
|
||||
var toolType = data.isTarget ? 'lesion' : 'nonTarget';
|
||||
var toolState = cornerstoneTools.globalImageIdSpecificToolStateManager.toolState;
|
||||
|
||||
// Loop through the timepoint data for this measurement
|
||||
Object.keys(data.timepoints).forEach(function(key) {
|
||||
var storedData = data.timepoints[key];
|
||||
var imageId = storedData.imageId;
|
||||
|
||||
if (!toolState[imageId]) {
|
||||
toolState[imageId] = {};
|
||||
}
|
||||
|
||||
if (!toolState[imageId][toolType]) {
|
||||
toolState[imageId][toolType] = {
|
||||
data: []
|
||||
};
|
||||
}
|
||||
|
||||
// Create measurementData structure based on the lesion data at this timepoint
|
||||
// We will add this into the toolData for this imageId
|
||||
var measurementData = storedData;
|
||||
measurementData.isTarget = data.isTarget;
|
||||
measurementData.lesionNumber = data.lesionNumber;
|
||||
measurementData.measurementText = data.measurementText;
|
||||
measurementData.lesionName = data.lesionName;
|
||||
measurementData.isDeleted = data.isDeleted;
|
||||
measurementData.location = data.location;
|
||||
measurementData.locationUID = data.locationUID;
|
||||
measurementData.patientId = patientId;
|
||||
measurementData.visible = data.visible;
|
||||
measurementData.active = data.active;
|
||||
measurementData.uid = data.uid;
|
||||
|
||||
toolState[imageId][toolType].data.push(measurementData);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Template.viewer.onDestroyed(function() {
|
||||
log.info("onDestroyed");
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/*! cornerstoneTools - v0.7.7 - 2015-11-21 | (c) 2014 Chris Hafey | https://github.com/chafey/cornerstoneTools */
|
||||
/*! cornerstoneTools - v0.7.7 - 2015-11-22 | (c) 2014 Chris Hafey | https://github.com/chafey/cornerstoneTools */
|
||||
// Begin Source: src/header.js
|
||||
if (typeof cornerstone === 'undefined') {
|
||||
cornerstone = {};
|
||||
@ -2111,40 +2111,6 @@ if (typeof cornerstoneTools === 'undefined') {
|
||||
}
|
||||
}
|
||||
|
||||
function drawArrow(context, start, end, color, lineWidth) {
|
||||
//variables to be used when creating the arrow
|
||||
var headLength = 10;
|
||||
|
||||
var angle = Math.atan2(end.y - start.y, end.x - start.x);
|
||||
|
||||
//starting path of the arrow from the start square to the end square and drawing the stroke
|
||||
context.beginPath();
|
||||
context.moveTo(start.x, start.y);
|
||||
context.lineTo(end.x, end.y);
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.stroke();
|
||||
|
||||
//starting a new path from the head of the arrow to one of the sides of the point
|
||||
context.beginPath();
|
||||
context.moveTo(end.x, end.y);
|
||||
context.lineTo(end.x - headLength * Math.cos(angle - Math.PI / 7), end.y - headLength * Math.sin(angle - Math.PI / 7));
|
||||
|
||||
//path from the side point of the arrow, to the other side point
|
||||
context.lineTo(end.x - headLength * Math.cos(angle + Math.PI / 7), end.y - headLength * Math.sin(angle + Math.PI / 7));
|
||||
|
||||
//path from the side point back to the tip of the arrow, and then again to the opposite side point
|
||||
context.lineTo(end.x, end.y);
|
||||
context.lineTo(end.x - headLength * Math.cos(angle - Math.PI / 7), end.y - headLength * Math.sin(angle - Math.PI / 7));
|
||||
|
||||
//draws the paths created above
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.stroke();
|
||||
context.fillStyle = color;
|
||||
context.fill();
|
||||
}
|
||||
|
||||
///////// BEGIN IMAGE RENDERING ///////
|
||||
function onImageRendered(e, eventData) {
|
||||
// if we have no toolData for this element, return immediately as there is nothing to do
|
||||
@ -2184,9 +2150,9 @@ if (typeof cornerstoneTools === 'undefined') {
|
||||
var handleEndCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.end);
|
||||
|
||||
if (config.arrowFirst) {
|
||||
drawArrow(context, handleEndCanvas, handleStartCanvas, color, lineWidth);
|
||||
cornerstoneTools.drawArrow(context, handleEndCanvas, handleStartCanvas, color, lineWidth);
|
||||
} else {
|
||||
drawArrow(context, handleStartCanvas, handleEndCanvas, color, lineWidth);
|
||||
cornerstoneTools.drawArrow(context, handleStartCanvas, handleEndCanvas, color, lineWidth);
|
||||
}
|
||||
|
||||
if (config.drawHandles) {
|
||||
@ -9792,6 +9758,52 @@ Display scroll progress bar across bottom of image.
|
||||
|
||||
// End Source; src/util/copyPoints.js
|
||||
|
||||
// Begin Source: src/util/drawArrow.js
|
||||
(function(cornerstoneTools) {
|
||||
|
||||
'use strict';
|
||||
|
||||
function drawArrow(context, start, end, color, lineWidth) {
|
||||
//variables to be used when creating the arrow
|
||||
var headLength = 10;
|
||||
|
||||
var angle = Math.atan2(end.y - start.y, end.x - start.x);
|
||||
|
||||
//starting path of the arrow from the start square to the end square and drawing the stroke
|
||||
context.beginPath();
|
||||
context.moveTo(start.x, start.y);
|
||||
context.lineTo(end.x, end.y);
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.stroke();
|
||||
|
||||
//starting a new path from the head of the arrow to one of the sides of the point
|
||||
context.beginPath();
|
||||
context.moveTo(end.x, end.y);
|
||||
context.lineTo(end.x - headLength * Math.cos(angle - Math.PI / 7), end.y - headLength * Math.sin(angle - Math.PI / 7));
|
||||
|
||||
//path from the side point of the arrow, to the other side point
|
||||
context.lineTo(end.x - headLength * Math.cos(angle + Math.PI / 7), end.y - headLength * Math.sin(angle + Math.PI / 7));
|
||||
|
||||
//path from the side point back to the tip of the arrow, and then again to the opposite side point
|
||||
context.lineTo(end.x, end.y);
|
||||
context.lineTo(end.x - headLength * Math.cos(angle - Math.PI / 7), end.y - headLength * Math.sin(angle - Math.PI / 7));
|
||||
|
||||
//draws the paths created above
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.stroke();
|
||||
context.fillStyle = color;
|
||||
context.fill();
|
||||
}
|
||||
|
||||
// Module exports
|
||||
cornerstoneTools.drawArrow = drawArrow;
|
||||
|
||||
})(cornerstoneTools);
|
||||
|
||||
// End Source; src/util/drawArrow.js
|
||||
|
||||
// Begin Source: src/util/drawEllipse.js
|
||||
(function(cornerstoneTools) {
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
var activeLesionMeasurementData;
|
||||
var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneTools) {
|
||||
|
||||
"use strict";
|
||||
@ -66,6 +65,8 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
||||
$(element).on('CornerstoneToolsMouseDown', eventData, cornerstoneTools.lesion.mouseDownCallback);
|
||||
$(element).on('CornerstoneToolsMouseDownActivate', eventData, cornerstoneTools.lesion.mouseDownActivateCallback);
|
||||
cornerstone.updateImage(element);
|
||||
|
||||
updateLesionCollection(measurementData);
|
||||
});
|
||||
}
|
||||
|
||||
@ -179,20 +180,8 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
||||
return cornerstoneMath.point.insideRect(coords, handle.boundingBox);
|
||||
}
|
||||
|
||||
function subscribeLesionToolSelectedEvent(element) {
|
||||
var elementEvents = $._data(element, "events");
|
||||
var index = Object.keys(elementEvents).indexOf("LesionToolSelected");
|
||||
if (index < 0) {
|
||||
// Subscribe LesionToolSelected and calls loadImage when lesion measurement is changed or updated.
|
||||
$(element).on("LesionToolSelected", loadImage);
|
||||
}
|
||||
|
||||
}
|
||||
///////// BEGIN IMAGE RENDERING ///////
|
||||
function onImageRendered(e, eventData) {
|
||||
|
||||
subscribeLesionToolSelectedEvent(e.currentTarget);
|
||||
|
||||
// if we have no toolData for this element, return immediately as there is nothing to do
|
||||
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
||||
if (!toolData) {
|
||||
@ -203,13 +192,91 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
||||
var context = eventData.canvasContext.canvas.getContext('2d');
|
||||
context.setTransform(1, 0, 0, 1, 0, 0);
|
||||
|
||||
var color;
|
||||
var element = eventData.element;
|
||||
var lineWidth = cornerstoneTools.toolStyle.getToolWidth();
|
||||
var config = cornerstoneTools.lesion.getConfiguration();
|
||||
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
renderLesion(toolData.data[i], context, eventData);
|
||||
var data = toolData.data[i];
|
||||
|
||||
context.save();
|
||||
|
||||
// configurable shadow from CornerstoneTools
|
||||
if (config && config.shadow) {
|
||||
context.shadowColor = '#000000';
|
||||
context.shadowOffsetX = 1;
|
||||
context.shadowOffsetY = 1;
|
||||
}
|
||||
|
||||
if (data.active) {
|
||||
color = cornerstoneTools.toolColors.getActiveColor();
|
||||
} else {
|
||||
color = cornerstoneTools.toolColors.getToolColor();
|
||||
}
|
||||
|
||||
// draw the line
|
||||
var handleStartCanvas = cornerstone.pixelToCanvas(element, data.handles.start);
|
||||
var handleEndCanvas = cornerstone.pixelToCanvas(element, data.handles.end);
|
||||
var canvasTextLocation = cornerstone.pixelToCanvas(element, data.handles.textBox);
|
||||
|
||||
context.beginPath();
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.moveTo(handleStartCanvas.x, handleStartCanvas.y);
|
||||
context.lineTo(handleEndCanvas.x, handleEndCanvas.y);
|
||||
context.stroke();
|
||||
|
||||
// draw the handles
|
||||
cornerstoneTools.drawHandles(context, eventData, data.handles, color);
|
||||
|
||||
if (data.lesionName) {
|
||||
//Draw linked line as dashed
|
||||
context.beginPath();
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.setLineDash([2, 3]);
|
||||
|
||||
var mid = {
|
||||
x: (handleStartCanvas.x + handleEndCanvas.x) / 2,
|
||||
y: (handleStartCanvas.y + handleEndCanvas.y) / 2
|
||||
};
|
||||
|
||||
context.moveTo(mid.x, mid.y);
|
||||
context.lineTo(canvasTextLocation.x + 20, canvasTextLocation.y + 20);
|
||||
context.stroke();
|
||||
|
||||
// Draw the text
|
||||
var dx = (data.handles.start.x - data.handles.end.x) * (eventData.image.columnPixelSpacing || 1);
|
||||
var dy = (data.handles.start.y - data.handles.end.y) * (eventData.image.rowPixelSpacing || 1);
|
||||
var length = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
var suffix = ' mm';
|
||||
if (!eventData.image.rowPixelSpacing || !eventData.image.columnPixelSpacing) {
|
||||
suffix = ' pixels';
|
||||
}
|
||||
|
||||
var text = '' + length.toFixed(2) + suffix;
|
||||
var textLines = [data.lesionName, text];
|
||||
|
||||
var boundingBox = cornerstoneTools.drawTextBox(context,
|
||||
textLines,
|
||||
canvasTextLocation.x, canvasTextLocation.y, color);
|
||||
|
||||
data.handles.textBox.boundingBox = boundingBox;
|
||||
|
||||
// Set measurement text to show lesion table
|
||||
data.measurementText = length.toFixed(1);
|
||||
}
|
||||
|
||||
context.restore();
|
||||
|
||||
updateLesionCollection(toolData.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function updateLesionCollection(lesionData) {
|
||||
// TODO = Remove this in favour of measurement events
|
||||
if (!lesionData.active) {
|
||||
return;
|
||||
}
|
||||
@ -217,176 +284,11 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
||||
if (lesionData.timepointID && lesionData.timepointID !== "") {
|
||||
// Update Measurements Collection
|
||||
measurementManagerDAL.updateTimepointData(lesionData);
|
||||
} else {
|
||||
activeLesionMeasurementData = lesionData;
|
||||
}
|
||||
}
|
||||
|
||||
function renderLesion(data, context, eventData) {
|
||||
context.save();
|
||||
|
||||
var color;
|
||||
var element = eventData.element;
|
||||
var lineWidth = cornerstoneTools.toolStyle.getToolWidth();
|
||||
var config = cornerstoneTools.lesion.getConfiguration();
|
||||
|
||||
// configurable shadow from CornerstoneTools
|
||||
if (config && config.shadow) {
|
||||
context.shadowColor = '#000000';
|
||||
context.shadowOffsetX = 1;
|
||||
context.shadowOffsetY = 1;
|
||||
}
|
||||
|
||||
if (data.active) {
|
||||
color = cornerstoneTools.toolColors.getActiveColor();
|
||||
} else {
|
||||
color = cornerstoneTools.toolColors.getToolColor();
|
||||
}
|
||||
|
||||
// draw the line
|
||||
var handleStartCanvas = cornerstone.pixelToCanvas(element, data.handles.start);
|
||||
var handleEndCanvas = cornerstone.pixelToCanvas(element, data.handles.end);
|
||||
var canvasTextLocation = cornerstone.pixelToCanvas(element, data.handles.textBox);
|
||||
|
||||
context.beginPath();
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.moveTo(handleStartCanvas.x, handleStartCanvas.y);
|
||||
context.lineTo(handleEndCanvas.x, handleEndCanvas.y);
|
||||
context.stroke();
|
||||
|
||||
// draw the handles
|
||||
cornerstoneTools.drawHandles(context, eventData, data.handles, color);
|
||||
|
||||
//Draw linked line as dashed
|
||||
context.setLineDash([2, 3]);
|
||||
context.beginPath();
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = 1 / eventData.viewport.scale;
|
||||
var mid = {
|
||||
x: (handleStartCanvas.x + handleEndCanvas.x) / 2,
|
||||
y: (handleStartCanvas.y + handleEndCanvas.y) / 2
|
||||
};
|
||||
|
||||
context.moveTo(mid.x, mid.y);
|
||||
context.lineTo(canvasTextLocation.x + 20, canvasTextLocation.y + 20);
|
||||
context.stroke();
|
||||
|
||||
// Draw the text
|
||||
var dx = (data.handles.start.x - data.handles.end.x) * (eventData.image.columnPixelSpacing || 1);
|
||||
var dy = (data.handles.start.y - data.handles.end.y) * (eventData.image.rowPixelSpacing || 1);
|
||||
var length = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
var suffix = ' mm';
|
||||
if (!eventData.image.rowPixelSpacing || !eventData.image.columnPixelSpacing) {
|
||||
suffix = ' pixels';
|
||||
}
|
||||
|
||||
var text = '' + length.toFixed(2) + suffix;
|
||||
var textLines = [data.lesionName, text];
|
||||
|
||||
var boundingBox = cornerstoneTools.drawTextBox(context,
|
||||
textLines,
|
||||
canvasTextLocation.x, canvasTextLocation.y, color);
|
||||
|
||||
data.handles.textBox.boundingBox = boundingBox;
|
||||
|
||||
// Set measurement text to show lesion table
|
||||
data.measurementText = length.toFixed(1);
|
||||
|
||||
// Lesion Measurement is changed
|
||||
$(element).trigger("LesionTextChanged", data);
|
||||
|
||||
context.restore();
|
||||
}
|
||||
|
||||
///////// END IMAGE RENDERING ///////
|
||||
|
||||
function updateLesion(e, eventData) {
|
||||
var enabledElement = eventData.enabledElement;
|
||||
var element = eventData.enabledElement.element;
|
||||
var isTarget = eventData.lesionData.isTarget;
|
||||
var lesionNumber = eventData.lesionData.lesionNumber;
|
||||
var type = eventData.type;
|
||||
|
||||
// if we have no toolData for this element, return immediately as there is nothing to do
|
||||
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
||||
if (!toolData) {
|
||||
return;
|
||||
}
|
||||
|
||||
var data,
|
||||
i;
|
||||
|
||||
switch (type) {
|
||||
case "delete":
|
||||
//If type is delete, remove measurement
|
||||
var deletedDataIndex = -1;
|
||||
|
||||
for (i = 0; i < toolData.data.length; i++) {
|
||||
data = toolData.data[i];
|
||||
|
||||
//When click a row of table measurements, measurement will be active and color will be green
|
||||
if (data.lesionNumber === lesionNumber && eventData.type !== "active" && isTarget) {
|
||||
data.visible = false;
|
||||
deletedDataIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (deletedDataIndex >= 0 && deletedDataIndex < toolData.data.length) {
|
||||
toolData.data.splice(deletedDataIndex, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case "active":
|
||||
for (i = 0; i < toolData.data.length; i++) {
|
||||
data = toolData.data[i];
|
||||
//When click a row of table measurements, measurement will be active and color will be green
|
||||
if (data.lesionNumber === lesionNumber && eventData.type === "active" && isTarget) {
|
||||
data.active = true;
|
||||
} else {
|
||||
data.active = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "inactive":
|
||||
for (i = 0; i < toolData.data.length; i++) {
|
||||
data = toolData.data[i];
|
||||
// Make inactive all lesions for the timepoint
|
||||
data.active = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cornerstone.updateImage(element);
|
||||
}
|
||||
|
||||
|
||||
// TODO=Refactor because this function is repeated in nonTargetTool!
|
||||
function loadImage(e, eventData) {
|
||||
// If type is active, load image and activate lesion
|
||||
// If type is inactive, update lesions of enabledElement as inactive
|
||||
log.info('lesionTool loadImage');
|
||||
var element = eventData.enabledElement.element;
|
||||
var imageId = eventData.lesionData.imageId;
|
||||
if (eventData.type === "active") {
|
||||
var stackToolDataSource = cornerstoneTools.getToolState(element, 'stack');
|
||||
var stackData = stackToolDataSource.data[0];
|
||||
var imageIdIndex = stackData.imageIds.indexOf(imageId);
|
||||
if (imageIdIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cornerstone.loadAndCacheImage(imageIds[imageIdIndex]).then(function(image) {
|
||||
cornerstone.displayImage(element, image);
|
||||
updateLesion(e, eventData);
|
||||
});
|
||||
} else if (eventData.type === "inactive") {
|
||||
updateLesion(e, eventData);
|
||||
}
|
||||
}
|
||||
|
||||
// module exports
|
||||
cornerstoneTools.lesion = cornerstoneTools.mouseButtonTool({
|
||||
createNewMeasurement: createNewMeasurement,
|
||||
|
||||
@ -23,8 +23,8 @@ var measurementManagerDAL = (function() {
|
||||
longestDiameter: lesionData.measurementText,
|
||||
imageId: lesionData.imageId,
|
||||
seriesInstanceUid: lesionData.seriesInstanceUid,
|
||||
studyInstanceUid: lesionData.studyInstanceUid
|
||||
|
||||
studyInstanceUid: lesionData.studyInstanceUid,
|
||||
handles: lesionData.handles
|
||||
};
|
||||
} else {
|
||||
// Add null measurement
|
||||
@ -32,22 +32,25 @@ var measurementManagerDAL = (function() {
|
||||
longestDiameter: "",
|
||||
imageId: "",
|
||||
seriesInstanceUid: "",
|
||||
studyInstanceUid: ""
|
||||
studyInstanceUid: "",
|
||||
handles: undefined
|
||||
};
|
||||
}
|
||||
timepointsObject[timepointId] = timepointObject;
|
||||
}
|
||||
|
||||
var lesionDataObject = {
|
||||
patientId: timepoints[0].patientId,
|
||||
lesionUID: uuid.v4(),
|
||||
number: Measurements.find().count() + 1,
|
||||
lesionNumber: lesionData.lesionNumber,
|
||||
isTarget: lesionData.isTarget,
|
||||
locationUID: lesionData.locationUID,
|
||||
location: getLocationName(lesionData.locationUID),
|
||||
timepoints: timepointsObject
|
||||
};
|
||||
var lesionDataObject = lesionData;
|
||||
|
||||
lesionDataObject.patientId = timepoints[0].patientId;
|
||||
lesionDataObject.location = getLocationName(lesionData.locationUID);
|
||||
lesionDataObject.timepoints = timepointsObject;
|
||||
|
||||
// Is there a use for this?
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
var element = mouseEventData.element;
|
||||
|
||||
function doneCallback(lesionNumber) {
|
||||
measurementData.lesionName = "Non-Target "+lesionNumber;
|
||||
measurementData.lesionName = "Non-Target " + lesionNumber;
|
||||
measurementData.lesionNumber = lesionNumber;
|
||||
measurementData.active = true;
|
||||
cornerstone.updateImage(element);
|
||||
@ -152,142 +152,88 @@
|
||||
return cornerstoneMath.point.insideRect(coords, handle.boundingBox);
|
||||
}
|
||||
|
||||
function drawArrow(context, start, end, color, lineWidth) {
|
||||
//variables to be used when creating the arrow
|
||||
var headLength = 10;
|
||||
|
||||
var angle = Math.atan2(end.y - start.y, end.x - start.x);
|
||||
|
||||
//starting path of the arrow from the start square to the end square and drawing the stroke
|
||||
context.beginPath();
|
||||
context.moveTo(start.x, start.y);
|
||||
context.lineTo(end.x, end.y);
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.stroke();
|
||||
|
||||
//starting a new path from the head of the arrow to one of the sides of the point
|
||||
context.beginPath();
|
||||
context.moveTo(end.x, end.y);
|
||||
context.lineTo(end.x - headLength * Math.cos(angle - Math.PI / 7), end.y - headLength * Math.sin(angle - Math.PI / 7));
|
||||
|
||||
//path from the side point of the arrow, to the other side point
|
||||
context.lineTo(end.x - headLength * Math.cos(angle + Math.PI / 7), end.y - headLength * Math.sin(angle + Math.PI / 7));
|
||||
|
||||
//path from the side point back to the tip of the arrow, and then again to the opposite side point
|
||||
context.lineTo(end.x, end.y);
|
||||
context.lineTo(end.x - headLength * Math.cos(angle - Math.PI / 7), end.y - headLength * Math.sin(angle - Math.PI / 7));
|
||||
|
||||
//draws the paths created above
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.stroke();
|
||||
context.fillStyle = color;
|
||||
context.fill();
|
||||
}
|
||||
|
||||
function subscribeNonTargetToolModifiedEvent(element) {
|
||||
var elementEvents = $._data(element, "events");
|
||||
var index = Object.keys(elementEvents).indexOf("NonTargetToolSelected");
|
||||
if (index < 0) {
|
||||
// Subscribe LesionToolModified and calls loadImage function when lesion measurement is changed or updated.
|
||||
$(element).on("NonTargetToolSelected", loadImage);
|
||||
}
|
||||
|
||||
}
|
||||
///////// BEGIN IMAGE RENDERING ///////
|
||||
function onImageRendered(e, eventData) {
|
||||
subscribeNonTargetToolModifiedEvent(e.currentTarget);
|
||||
var element = eventData.element;
|
||||
|
||||
// if we have no toolData for this element, return immediately as there is nothing to do
|
||||
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
||||
if (toolData === undefined) {
|
||||
var toolData = cornerstoneTools.getToolState(element, toolType);
|
||||
if (!toolData) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateLesions(toolData, eventData);
|
||||
}
|
||||
|
||||
function updateLesions(toolData, eventData) {
|
||||
// we have tool data for this element - iterate over each one and draw it
|
||||
var context = eventData.canvasContext.canvas.getContext('2d');
|
||||
context.setTransform(1, 0, 0, 1, 0, 0);
|
||||
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
renderLesion(toolData.data[i], context, eventData);
|
||||
}
|
||||
}
|
||||
|
||||
function renderLesion(lesion, context, eventData) {
|
||||
context.save();
|
||||
|
||||
var color;
|
||||
var lineWidth = cornerstoneTools.toolStyle.getToolWidth();
|
||||
var font = cornerstoneTools.textStyle.getFont();
|
||||
var config = cornerstoneTools.nonTarget.getConfiguration();
|
||||
|
||||
// configurable shadow from CornerstoneTools
|
||||
if (config && config.shadow) {
|
||||
context.shadowColor = '#000000';
|
||||
context.shadowOffsetX = +1;
|
||||
context.shadowOffsetY = +1;
|
||||
context.font = font;
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
var data = toolData.data[i];
|
||||
|
||||
context.save();
|
||||
|
||||
// configurable shadow from CornerstoneTools
|
||||
if (config && config.shadow) {
|
||||
context.shadowColor = '#000000';
|
||||
context.shadowOffsetX = +1;
|
||||
context.shadowOffsetY = +1;
|
||||
}
|
||||
|
||||
if (data.active) {
|
||||
color = cornerstoneTools.toolColors.getActiveColor();
|
||||
} else {
|
||||
color = cornerstoneTools.toolColors.getToolColor();
|
||||
}
|
||||
|
||||
// Draw the arrow
|
||||
var handleStartCanvas = cornerstone.pixelToCanvas(element, data.handles.start);
|
||||
var handleEndCanvas = cornerstone.pixelToCanvas(element, data.handles.end);
|
||||
var canvasTextLocation = cornerstone.pixelToCanvas(element, data.handles.textBox);
|
||||
|
||||
if (config.arrowFirst) {
|
||||
cornerstoneTools.drawArrow(context, handleEndCanvas, handleStartCanvas, color, lineWidth);
|
||||
} else {
|
||||
cornerstoneTools.drawArrow(context, handleStartCanvas, handleEndCanvas, color, lineWidth);
|
||||
}
|
||||
|
||||
if (config.drawHandles) {
|
||||
cornerstoneTools.drawHandles(context, eventData, data.handles, color);
|
||||
} else if (config.drawHandlesOnHover && data.handles.start.active) {
|
||||
cornerstoneTools.drawHandles(context, eventData, [ lesion.handles.start ], color);
|
||||
} else if (config.drawHandlesOnHover && data.handles.end.active) {
|
||||
cornerstoneTools.drawHandles(context, eventData, [ lesion.handles.end ], color);
|
||||
}
|
||||
|
||||
// Draw the text
|
||||
if (data.lesionName && data.lesionName !== '') {
|
||||
//Draw linked line as dashed
|
||||
var mid = {
|
||||
x: (handleStartCanvas.x + handleEndCanvas.x) / 2,
|
||||
y: (handleStartCanvas.y + handleEndCanvas.y) / 2
|
||||
};
|
||||
|
||||
context.beginPath();
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = lineWidth;
|
||||
context.setLineDash([2, 3]);
|
||||
|
||||
context.moveTo(mid.x, mid.y);
|
||||
context.lineTo(canvasTextLocation.x + 20, canvasTextLocation.y + 20);
|
||||
context.stroke();
|
||||
|
||||
var boundingBox = cornerstoneTools.drawTextBox(context, data.lesionName, canvasTextLocation.x, canvasTextLocation.y, color);
|
||||
data.handles.textBox.boundingBox = boundingBox;
|
||||
}
|
||||
|
||||
context.restore();
|
||||
}
|
||||
|
||||
if (lesion.active) {
|
||||
color = cornerstoneTools.toolColors.getActiveColor();
|
||||
} else {
|
||||
color = cornerstoneTools.toolColors.getToolColor();
|
||||
}
|
||||
|
||||
// Draw the arrow
|
||||
var handleStartCanvas = cornerstone.pixelToCanvas(eventData.element, lesion.handles.start);
|
||||
var handleEndCanvas = cornerstone.pixelToCanvas(eventData.element, lesion.handles.end);
|
||||
var canvasTextLocation = cornerstone.pixelToCanvas(eventData.element, lesion.handles.textBox);
|
||||
|
||||
if (config.arrowFirst) {
|
||||
drawArrow(context, handleEndCanvas, handleStartCanvas, color, lineWidth);
|
||||
} else {
|
||||
drawArrow(context, handleStartCanvas, handleEndCanvas, color, lineWidth);
|
||||
}
|
||||
|
||||
if (config.drawHandles) {
|
||||
cornerstoneTools.drawHandles(context, eventData, lesion.handles, color);
|
||||
} else if (config.drawHandlesOnHover && lesion.handles.start.active) {
|
||||
cornerstoneTools.drawHandles(context, eventData, [ lesion.handles.start ], color);
|
||||
} else if (config.drawHandlesOnHover && lesion.handles.end.active) {
|
||||
cornerstoneTools.drawHandles(context, eventData, [ lesion.handles.end ], color);
|
||||
}
|
||||
|
||||
//Draw linked line as dashed
|
||||
var mid = {
|
||||
x: (handleStartCanvas.x + handleEndCanvas.x) / 2,
|
||||
y: (handleStartCanvas.y + handleEndCanvas.y) / 2
|
||||
};
|
||||
context.setLineDash([2, 3]);
|
||||
context.beginPath();
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = 1 / eventData.viewport.scale;
|
||||
mid = {
|
||||
x: mid.x,
|
||||
y: mid.y
|
||||
};
|
||||
|
||||
context.moveTo(mid.x, mid.y);
|
||||
context.lineTo(canvasTextLocation.x + 20, canvasTextLocation.y + 20);
|
||||
context.stroke();
|
||||
|
||||
|
||||
// Draw the text
|
||||
if (lesion.lesionName && lesion.lesionName !== '') {
|
||||
context.font = font;
|
||||
var boundingBox = cornerstoneTools.drawTextBox(context, lesion.lesionName, canvasTextLocation.x, canvasTextLocation.y, color);
|
||||
lesion.handles.textBox.boundingBox = boundingBox;
|
||||
}
|
||||
|
||||
|
||||
context.restore();
|
||||
|
||||
}
|
||||
|
||||
// ---- Touch tool ----
|
||||
|
||||
///////// BEGIN ACTIVE TOOL ///////
|
||||
@ -295,7 +241,7 @@
|
||||
var element = touchEventData.element;
|
||||
|
||||
function doneCallback(lesionNumber) {
|
||||
measurementData.lesionName = "Non-Target "+lesionNumber;
|
||||
measurementData.lesionName = "Non-Target " + lesionNumber;
|
||||
measurementData.lesionNumber = lesionNumber;
|
||||
measurementData.active = true;
|
||||
cornerstone.updateImage(element);
|
||||
@ -377,114 +323,6 @@
|
||||
return false; // false = causes jquery to preventDefault() and stopPropagation() this event
|
||||
}
|
||||
|
||||
function updateLesion(e, eventObject) {
|
||||
var start = new Date();
|
||||
|
||||
var enabledElement = eventObject.enabledElement;
|
||||
var isTarget = eventObject.lesionData.isTarget;
|
||||
var lesionNumber = eventObject.lesionData.lesionNumber;
|
||||
var seriesInstanceUid = eventObject.lesionData.seriesInstanceUid;
|
||||
var studyInstanceUid = eventObject.lesionData.studyInstanceUid;
|
||||
var type = eventObject.type;
|
||||
|
||||
// if we have no toolData for this element, return immediately as there is nothing to do
|
||||
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
||||
if (!toolData) {
|
||||
return;
|
||||
}
|
||||
|
||||
//If type is delete, remove measurement
|
||||
if (type === "delete") {
|
||||
var deletedDataIndex = -1;
|
||||
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
var data = toolData.data[i];
|
||||
|
||||
//When click a row of table measurements, measurement will be active and color will be green
|
||||
if (data.lesionNumber === lesionNumber
|
||||
&& eventObject.type !== "active"
|
||||
&& !isTarget
|
||||
&& data.seriesInstanceUid === seriesInstanceUid
|
||||
&& data.studyInstanceUid === studyInstanceUid) {
|
||||
|
||||
data.visible = false;
|
||||
deletedDataIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (deletedDataIndex >= 0 && deletedDataIndex < toolData.data.length) {
|
||||
toolData.data.splice(deletedDataIndex, 1);
|
||||
}
|
||||
} else if (type === "active") {
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
var data = toolData.data[i];
|
||||
//When click a row of table measurements, measurement will be active and color will be green
|
||||
if (data.lesionNumber === eventObject.lesionData.lesionNumber
|
||||
&& eventObject.type === "active"
|
||||
&& !isTarget
|
||||
&& data.seriesInstanceUid === seriesInstanceUid
|
||||
&& data.studyInstanceUid === studyInstanceUid) {
|
||||
|
||||
data.active = true;
|
||||
} else {
|
||||
data.active = false;
|
||||
}
|
||||
}
|
||||
} else if (type === "inactive") {
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
var data = toolData.data[i];
|
||||
// Make inactive all lesions for the timepoint
|
||||
data.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
var context = enabledElement.canvas.getContext('2d');
|
||||
|
||||
var end = new Date();
|
||||
var diff = end - start;
|
||||
//console.log(diff + ' ms');
|
||||
|
||||
var eventData = {
|
||||
viewport: enabledElement.viewport,
|
||||
element: enabledElement.element,
|
||||
image: enabledElement.image,
|
||||
enabledElement: enabledElement,
|
||||
canvasContext: context,
|
||||
measurementText: "",
|
||||
renderTimeInMs: diff,
|
||||
lesionNumber: lesionNumber,
|
||||
isTarget: isTarget,
|
||||
type: type //Holds image will be deleted or active
|
||||
};
|
||||
|
||||
enabledElement.invalid = false;
|
||||
|
||||
onImageRendered(e, eventData);
|
||||
}
|
||||
|
||||
function loadImage(e, eventData) {
|
||||
// If type is active, load image and activate lesion
|
||||
// If type is inactive, update lesions of enabledElement as inactive
|
||||
log.info('nonTargetTool loadImage');
|
||||
var element = eventData.enabledElement.element;
|
||||
var imageId = eventData.lesionData.imageId;
|
||||
if (eventData.type === "active") {
|
||||
var stackToolDataSource = cornerstoneTools.getToolState(element, 'stack');
|
||||
var stackData = stackToolDataSource.data[0];
|
||||
var imageIdIndex = stackData.imageIds.indexOf(imageId);
|
||||
if (imageIdIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cornerstone.loadAndCacheImage(stackData.imageIds[imageIdIndex]).then(function(image) {
|
||||
cornerstone.displayImage(element, image);
|
||||
updateLesion(e, eventData);
|
||||
});
|
||||
} else if (eventData.type === "inactive") {
|
||||
updateLesion(e, eventData);
|
||||
}
|
||||
}
|
||||
|
||||
cornerstoneTools.nonTarget = cornerstoneTools.mouseButtonTool({
|
||||
addNewMeasurement: addNewMeasurement,
|
||||
createNewMeasurement: createNewMeasurement,
|
||||
|
||||
@ -1,74 +1,3 @@
|
||||
/**
|
||||
* Returns timepoint object based on timepoint id of the enabled element
|
||||
*
|
||||
* @param timepoints
|
||||
* @param enabledElement
|
||||
* @returns {*|{}} Timepoint object based on timepoint id of the enabled element (or an empty Object)
|
||||
*/
|
||||
function getTimepointObject(imageId) {
|
||||
var study = cornerstoneTools.metaData.get('study', imageId);
|
||||
|
||||
var timepoint = Timepoints.findOne({timepointName: study.studyDate});
|
||||
return timepoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to the image of the correct image index
|
||||
* Activate the selected measurement on the switched image (color to be green)
|
||||
* Deactivate all other measurements on the switched image (color to be white)
|
||||
*/
|
||||
function activateMeasurements(element, measurementId) {
|
||||
// TODO=Switch this to use the new CornerstoneToolMeasurementModified event,
|
||||
// Once it has 'modified on activation' set up
|
||||
|
||||
var enabledElement = cornerstone.getEnabledElement(element);
|
||||
var imageId = enabledElement.image.imageId;
|
||||
var timepointData = getTimepointObject(imageId);
|
||||
var measurementData = Measurements.findOne(measurementId);
|
||||
|
||||
var measurementAtTimepoint = measurementData.timepoints[timepointData.timepointID];
|
||||
if (!measurementAtTimepoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Defines event data
|
||||
var eventData = {
|
||||
enabledElement: enabledElement,
|
||||
lesionData: {
|
||||
id: measurementId,
|
||||
isTarget: measurementData.isTarget,
|
||||
lesionNumber: measurementData.lesionNumber,
|
||||
imageId: imageId,
|
||||
seriesInstanceUid: measurementAtTimepoint.seriesInstanceUid,
|
||||
studyInstanceUid: measurementAtTimepoint.studyInstanceUid
|
||||
},
|
||||
type: "active"
|
||||
};
|
||||
|
||||
// If isTarget = false, this measurement is nonTarget measurement
|
||||
// Activate related nonTarget measurement
|
||||
// Deactivate all target measurements to activate only nonTarget measurement
|
||||
if (!isTarget) {
|
||||
$(element).trigger("NonTargetToolSelected", eventData);
|
||||
|
||||
// Deactivate lesion tool measurements
|
||||
eventData.type = "inactive";
|
||||
|
||||
$(element).trigger("LesionToolSelected", eventData);
|
||||
|
||||
} else {
|
||||
// Trigger event for target measurements
|
||||
$(element).trigger("LesionToolSelected", eventData);
|
||||
|
||||
// Deactivate nonTarget tool measurements
|
||||
eventData.type = "inactive";
|
||||
|
||||
// Trigger event for nonTarget measurements
|
||||
// Inactivate all nonTarget measurements if any measurement is active
|
||||
$(element).trigger("NonTargetToolSelected", eventData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates a set of lesions when lesion table row is clicked
|
||||
*
|
||||
@ -87,25 +16,45 @@ function activateLesion(measurementId) {
|
||||
// Get the timepoint data from this Measurement
|
||||
var timepoints = measurementData.timepoints;
|
||||
|
||||
// Get all non-dummy timepoint entries in the Measurement
|
||||
// TODO=Re-evaluate this approach to populating viewports with timepoints
|
||||
// What is the desired behaviour here?
|
||||
var timepointsWithEntries = [];
|
||||
Object.keys(timepoints).forEach(function(key) {
|
||||
var timepoint = timepoints[key];
|
||||
|
||||
if (timepoint.imageId === "" ||
|
||||
timepoint.studyInstanceUid === "" ||
|
||||
timepoint.seriesInstanceUid === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
timepointsWithEntries.push(timepoint);
|
||||
});
|
||||
|
||||
// If there are no non-dummy timepoint entries, stop here
|
||||
if (!timepointsWithEntries.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through the viewports and display each timepoint
|
||||
$(".imageViewerViewport").each(function(viewportIndex, element) {
|
||||
// Stop if we run out of timepoints before viewports
|
||||
if (viewportIndex >= Object.keys(timepoints).length) {
|
||||
if (viewportIndex >= timepointsWithEntries.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find measurements related to the Nth timepoint
|
||||
// TODO=Re-evaluate this approach to populating viewports with timepoints
|
||||
// What is the desired behaviour here?
|
||||
var measurementAtTimepoint = timepointsWithEntries[viewportIndex];
|
||||
|
||||
// Find the image that is currently in this viewport
|
||||
var enabledElement = cornerstone.getEnabledElement(element);
|
||||
if (!enabledElement || !enabledElement.image) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find measurements related to the Nth timepoint
|
||||
// TODO=Re-evaluate this approach to populating viewports with timepoints
|
||||
// What is the desired behaviour here?
|
||||
var key = Object.keys(measurementData.timepoints)[viewportIndex];
|
||||
var measurementAtTimepoint = measurementData.timepoints[key];
|
||||
|
||||
// If there is no measurement data to display, stop here
|
||||
if (!measurementAtTimepoint) {
|
||||
return;
|
||||
@ -134,6 +83,115 @@ function activateLesion(measurementId) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns timepoint object based on timepoint id of the enabled element
|
||||
*
|
||||
* @param timepoints
|
||||
* @param enabledElement
|
||||
* @returns {*|{}} Timepoint object based on timepoint id of the enabled element (or an empty Object)
|
||||
*/
|
||||
function getTimepointObject(imageId) {
|
||||
var study = cornerstoneTools.metaData.get('study', imageId);
|
||||
return Timepoints.findOne({timepointName: study.studyDate});
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to the image of the correct image index
|
||||
* Activate the selected measurement on the switched image (color to be green)
|
||||
* Deactivate all other measurements on the switched image (color to be white)
|
||||
*/
|
||||
function activateMeasurements(element, measurementId) {
|
||||
// TODO=Switch this to use the new CornerstoneToolMeasurementModified event,
|
||||
// Once it has 'modified on activation' set up
|
||||
|
||||
var enabledElement = cornerstone.getEnabledElement(element);
|
||||
var imageId = enabledElement.image.imageId;
|
||||
var timepointData = getTimepointObject(imageId);
|
||||
var measurementData = Measurements.findOne(measurementId);
|
||||
|
||||
var measurementAtTimepoint = measurementData.timepoints[timepointData.timepointID];
|
||||
if (!measurementAtTimepoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If type is active, load image and activate lesion
|
||||
// If type is inactive, update lesions of enabledElement as inactive
|
||||
var stackToolDataSource = cornerstoneTools.getToolState(element, 'stack');
|
||||
var stackData = stackToolDataSource.data[0];
|
||||
var imageIds = stackData.imageIds;
|
||||
var imageIdIndex = imageIds.indexOf(measurementAtTimepoint.imageId);
|
||||
|
||||
if (imageIdIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (imageIdIndex === stackData.currentImageIdIndex){
|
||||
activateTool(element, measurementData, timepointData.timepointID);
|
||||
} else {
|
||||
cornerstone.loadAndCacheImage(imageIds[imageIdIndex]).then(function(image) {
|
||||
cornerstone.displayImage(element, image);
|
||||
activateTool(element, measurementData, timepointData.timepointID);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates a specific tool data instance and deactivates all other
|
||||
* target and non-target measurement data
|
||||
*
|
||||
* @param element
|
||||
* @param measurementData
|
||||
* @param timepointID
|
||||
*/
|
||||
function activateTool(element, measurementData, timepointID) {
|
||||
deactivateAllToolData(element, 'lesion');
|
||||
deactivateAllToolData(element, 'nonTarget');
|
||||
|
||||
var toolType = measurementData.isTarget ? 'lesion' : 'nonTarget';
|
||||
var toolData = cornerstoneTools.getToolState(element, toolType);
|
||||
if (!toolData) {
|
||||
return;
|
||||
}
|
||||
|
||||
var measurementAtTimepoint = measurementData.timepoints[timepointID];
|
||||
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
data = toolData.data[i];
|
||||
|
||||
// When click a row of table measurements, measurement will be active and color will be green
|
||||
// TODO= Remove this with the measurementId once it is in the tool data
|
||||
if (data.seriesInstanceUid === measurementAtTimepoint.seriesInstanceUid &&
|
||||
data.studyInstanceUid === measurementAtTimepoint.studyInstanceUid &&
|
||||
data.lesionNumber === measurementData.lesionNumber &&
|
||||
data.isTarget == measurementData.isTarget) {
|
||||
|
||||
data.active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cornerstone.updateImage(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all tool data entries value for 'active' to false
|
||||
* This is used to remove the active color on entire sets of tools
|
||||
*
|
||||
* @param element The Cornerstone element that is being used
|
||||
* @param toolType The tooltype of the tools that will be deactivated
|
||||
*/
|
||||
function deactivateAllToolData(element, toolType) {
|
||||
var toolData = cornerstoneTools.getToolState(element, toolType);
|
||||
if (!toolData) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
var data = toolData.data[i];
|
||||
data.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
Template.lesionTable.helpers({
|
||||
'measurement': function() {
|
||||
return Measurements.find({}, {sort: {number: 1}});
|
||||
|
||||
@ -198,7 +198,7 @@ function loadSeriesIntoViewport(data) {
|
||||
// Use the tool manager to enable the currently active tool for this
|
||||
// newly rendered element
|
||||
var activeTool = toolManager.getActiveTool();
|
||||
toolManager.setActiveTool(activeTool);
|
||||
toolManager.setActiveTool(activeTool, element);
|
||||
|
||||
// Define a function to run whenever the Cornerstone viewport is rendered
|
||||
// (e.g. following a change of window or zoom)
|
||||
@ -382,6 +382,7 @@ Template.imageViewerViewport.onRendered(function() {
|
||||
currentImageIdIndex: this.data.currentImageIdIndex,
|
||||
studyInstanceUid: this.data.studyInstanceUid,
|
||||
seriesInstanceUid: this.data.seriesInstanceUid,
|
||||
renderedCallback: this.data.renderedCallback,
|
||||
activeViewport: activeViewport
|
||||
};
|
||||
|
||||
|
||||
@ -112,7 +112,9 @@ Template.toolbar.events({
|
||||
'click .imageViewerTool': function(e) {
|
||||
var tool = e.currentTarget.id;
|
||||
console.log('Setting active tool to: ' + tool);
|
||||
toolManager.setActiveTool(tool);
|
||||
|
||||
var elements = $('.imageViewerViewport');
|
||||
toolManager.setActiveTool(tool, elements);
|
||||
},
|
||||
'click .imageViewerCommand': function(e) {
|
||||
var command = e.currentTarget.id;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
var activeTool;
|
||||
|
||||
var alwaysEnabledTools;
|
||||
var alwaysEnabledTools = [];
|
||||
|
||||
var tools = {};
|
||||
|
||||
@ -77,7 +77,72 @@ toolManager = {
|
||||
setAlwaysEnabledTools: function(tools) {
|
||||
alwaysEnabledTools = tools;
|
||||
},
|
||||
setActiveTool: function(tool) {
|
||||
setActiveToolForElement: function(tool, element) {
|
||||
var canvases = $(element).find('canvas');
|
||||
if (element.classList.contains('empty') || !canvases.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First, deactivate the current active tool
|
||||
tools[activeTool].mouse.deactivate(element, 1);
|
||||
|
||||
if (tools[activeTool].touch) {
|
||||
tools[activeTool].touch.deactivate(element);
|
||||
}
|
||||
|
||||
// Enable any tools set as 'Always enabled'
|
||||
alwaysEnabledTools.forEach(function(toolType) {
|
||||
cornerstoneTools[toolType].enable(element);
|
||||
});
|
||||
|
||||
// Get the stack toolData
|
||||
var toolData = cornerstoneTools.getToolState(element, 'stack');
|
||||
if (!toolData || !toolData.data || !toolData.data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the imageIds for this element
|
||||
var imageIds = toolData.data[0].imageIds;
|
||||
|
||||
// Deactivate all the middle mouse, right click, and scroll wheel tools
|
||||
cornerstoneTools.pan.deactivate(element);
|
||||
cornerstoneTools.zoom.deactivate(element);
|
||||
cornerstoneTools.zoomWheel.deactivate(element);
|
||||
cornerstoneTools.stackScrollWheel.deactivate(element);
|
||||
|
||||
// Reactivate the relevant scrollwheel tool for this element
|
||||
if (imageIds.length > 1) {
|
||||
// scroll is the default tool for middle mouse wheel for stacks
|
||||
cornerstoneTools.stackScrollWheel.activate(element);
|
||||
} else {
|
||||
// zoom is the default tool for middle mouse wheel for single images (non stacks)
|
||||
cornerstoneTools.zoomWheel.activate(element);
|
||||
}
|
||||
|
||||
// This block ensures that the middle mouse and scroll tools keep working
|
||||
if (tool === 'pan') {
|
||||
cornerstoneTools.pan.activate(element, 3); // 3 means left mouse button and middle mouse button
|
||||
cornerstoneTools.zoom.activate(element, 4); // zoom is the default tool for right mouse button
|
||||
} else if (tool === 'zoom') {
|
||||
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
||||
cornerstoneTools.zoom.activate(element, 5); // 5 means left mouse button and right mouse button
|
||||
} else {
|
||||
// Reactivate the middle mouse and right click tools
|
||||
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
||||
cornerstoneTools.zoom.activate(element, 4); // zoom is the default tool for right mouse button
|
||||
|
||||
// Activate the chosen tool
|
||||
tools[tool].mouse.activate(element, 1);
|
||||
}
|
||||
|
||||
if (tools[tool].touch) {
|
||||
tools[tool].touch.activate(element);
|
||||
}
|
||||
|
||||
cornerstoneTools.zoomTouchPinch.activate(element);
|
||||
cornerstoneTools.panMultiTouch.activate(element);
|
||||
},
|
||||
setActiveTool: function(tool, elements) {
|
||||
if (!initialized) {
|
||||
toolManager.init();
|
||||
}
|
||||
@ -86,70 +151,9 @@ toolManager = {
|
||||
var toolButton = document.getElementById(tool);
|
||||
toolButton.classList.add('active');
|
||||
|
||||
$('.imageViewerViewport').each(function(index, element) {
|
||||
var canvases = $(element).find('canvas');
|
||||
if (element.classList.contains('empty') || !canvases.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First, deactivate the current active tool
|
||||
tools[activeTool].mouse.deactivate(element, 1);
|
||||
|
||||
if (tools[activeTool].touch) {
|
||||
tools[activeTool].touch.deactivate(element);
|
||||
}
|
||||
|
||||
// Enable any tools set as 'Always enabled'
|
||||
alwaysEnabledTools.forEach(function(toolType) {
|
||||
cornerstoneTools[toolType].enable(element);
|
||||
});
|
||||
|
||||
// Get the stack toolData
|
||||
var toolData = cornerstoneTools.getToolState(element, 'stack');
|
||||
if (!toolData || !toolData.data || !toolData.data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the imageIds for this element
|
||||
var imageIds = toolData.data[0].imageIds;
|
||||
|
||||
// Deactivate all the middle mouse, right click, and scroll wheel tools
|
||||
cornerstoneTools.pan.deactivate(element);
|
||||
cornerstoneTools.zoom.deactivate(element);
|
||||
cornerstoneTools.zoomWheel.deactivate(element);
|
||||
cornerstoneTools.stackScrollWheel.deactivate(element);
|
||||
|
||||
// Reactivate the relevant scrollwheel tool for this element
|
||||
if (imageIds.length > 1) {
|
||||
// scroll is the default tool for middle mouse wheel for stacks
|
||||
cornerstoneTools.stackScrollWheel.activate(element);
|
||||
} else {
|
||||
// zoom is the default tool for middle mouse wheel for single images (non stacks)
|
||||
cornerstoneTools.zoomWheel.activate(element);
|
||||
}
|
||||
|
||||
// This block ensures that the middle mouse and scroll tools keep working
|
||||
if (tool === 'pan') {
|
||||
cornerstoneTools.pan.activate(element, 3); // 3 means left mouse button and middle mouse button
|
||||
cornerstoneTools.zoom.activate(element, 4); // zoom is the default tool for right mouse button
|
||||
} else if (tool === 'zoom') {
|
||||
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
||||
cornerstoneTools.zoom.activate(element, 5); // 5 means left mouse button and right mouse button
|
||||
} else {
|
||||
// Reactivate the middle mouse and right click tools
|
||||
cornerstoneTools.pan.activate(element, 2); // pan is the default tool for middle mouse button
|
||||
cornerstoneTools.zoom.activate(element, 4); // zoom is the default tool for right mouse button
|
||||
|
||||
// Activate the chosen tool
|
||||
tools[tool].mouse.activate(element, 1);
|
||||
}
|
||||
|
||||
if (tools[tool].touch) {
|
||||
tools[tool].touch.activate(element);
|
||||
}
|
||||
|
||||
cornerstoneTools.zoomTouchPinch.activate(element);
|
||||
cornerstoneTools.panMultiTouch.activate(element);
|
||||
// Otherwise, set the active tool for all viewport elements
|
||||
$(elements).each(function(index, element) {
|
||||
toolManager.setActiveToolForElement(tool, element);
|
||||
});
|
||||
activeTool = tool;
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user