Updates to Lesion Tracker lesionTable and Packaging

This commit is contained in:
Erik Ziegler 2015-10-23 18:21:46 +02:00
parent 4721400b34
commit e2000480d3
36 changed files with 480 additions and 176 deletions

View File

@ -34,3 +34,4 @@ stylus
fortawesome:fontawesome
random
reactive-var
lesiontracker

View File

@ -50,6 +50,7 @@ iron:router@1.0.12
iron:url@1.0.11
jquery@1.11.4
launch-screen@1.0.4
lesiontracker@0.0.1
livedata@1.0.15
localstorage@1.0.5
logging@1.0.8

View File

@ -1,26 +0,0 @@
<template name="layoutLesionTracker">
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">
<img height="30px" src="/images/logo.png">
<h4 class="name">OHIF Lesion Tracker</h4>
</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li>
<a href="http://www.tumormetrics.org">About</a>
</li>
</ul>
</div>
</div>
</nav>
{{> yield}}
</template>

View File

@ -1,33 +0,0 @@
.navbar
margin-bottom: 0
border-radius: 0
color: #888888
background-color: #060606
border: none
font-family: "Sanchez"
color: #C1C1C1
.navbar-default .navbar-nav > li > a
color: #C1C1C1
font-weight: bold
font-size: 12pt
.navbar-form
margin: 0
padding: 15px 3px
.navbar-brand
img
float: left
margin-right: 10px
margin-top: -8px
h4.name
float: left
margin: 0
font-family: "Sanchez"
color: #C1C1C1
@media (min-width: 768px)
.navbar
border-radius: 0px

View File

@ -1,23 +0,0 @@
Template.lesionDialog.onRendered(function () {
// Listen lesionMeaurementCreated Event and when this event is triggered, show lesionLocationDialog Box
var viewportIndex = this.data.activeViewport.get();
$(document).on("LesionMeasurementCreated",function(e, eventData){
console.log("lesionMeasurementCreated");
var data = {};
data.viewportIndex = viewportIndex;
//Set Lesion Table Data to insert into lesion table
setLesionTableData(data);
if( !Session.get("lesionLocationSelected") ) {
$("#modal-dialog-container").css({
"top": eventData.currentPoints.page.y,
"left": eventData.currentPoints.page.x
});
$("#lesionDialog").modal("show");
}
});
});

View File

@ -1,15 +0,0 @@
<template name="lesionMeasurementContainer">
<div class="lesionMeasurementContainer">
<table class="lesionTable" id="tblLesion">
<thead>
<tr class="headRow">
<th>#</th>
<th>Location</th>
<th>LD</th>
<th style="text-align: center;"><i class="fa fa-times fa-lg"></i></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</template>

View File

@ -1,28 +0,0 @@
var lesionTableData;
setLesionTableData = function (data) {
lesionTableData = data;
};
getLesionTableData = function () {
return lesionTableData;
};
returnTblStr = function (obj) {
return '<tr id="' + obj.lineIndex + '" toolType="' + obj.toolType + '"><td class="tblRow">1</td><td class="tblRow">' + obj.lesionLocationObj.location + '</td><td class="tblRow">' + obj.lesions + '</td><td id="' + obj.lineIndex + '" toolType="' + obj.toolType + '"><button type="button" class="btnRemove fa fa-times fa-lg" title="Remove"></button></td></tr>';
};
Template.lesionMeasurementContainer.onRendered( function () {
console.log("rendered lesion");
//Link lesionLocationSelected event
$(document).on("lesionLocationSelected",function(event,data ){
var lesionData = getLesionTableData();
lesionData.lesionLocationObj = data;
var tabId = lesionData.tabId;
var el_index = lesionData.viewportIndex;
var lesionTables = $(".lesionTable");
var tableEl = lesionTables.get(el_index);
var tblStr = returnTblStr(lesionData);
$(tableEl).append(tblStr);
});
});

View File

@ -1,21 +0,0 @@
.lesionMeasurementContainer
width: 24%
float: left
height: 100%
#tblLesion {
overflow: auto;
border: solid 1px white;
padding: 0;
margin: 0 auto;
font-size: 14px;
cursor: pointer;
color: white;
width: 100%;
height:100%;
background-color: black;
}
#tblLesion > tr {background-color: #545454;border-bottom: solid 1px black; width: 100%;}
#tblLesion > tr.headRow{background-color: #424242;width: 100%; line-height: 15px;}
#tblLesion > tr.headRow th{padding:5px;text-align: left;font-style: italic;font-size:14px;}

View File

@ -1,5 +0,0 @@
<template name="lesionTableContainer">
<div class="lesionTableContainer">
Current, Prior, Nadir, Baseline go here
</div>
</template>

View File

@ -1,7 +0,0 @@
.lesionTableContainer
height: 25%
max-height: 200px
color: #A0A0A0
background-color: #2F2F2F
border: 8px solid #484848

View File

@ -1,4 +1,4 @@
<template name="lesionTrackerLayout">
<template name="layoutLesionTracker">
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">

View File

@ -4,4 +4,9 @@
margin: 0;
padding: 0;
background-color: black;
}
#upperHalf {
height: 75%;
width: 100%;
}

View File

@ -1,8 +1,10 @@
<template name="viewer">
<div id="viewer" class="viewer">
{{ >lesionDialog studies=studies activeViewport=activeViewport}}
{{ >hidingPanel studies=studies activeViewport=activeViewport}}
{{ >viewerMain studies=studies activeViewport=activeViewport viewportRows=viewportRows viewportColumns=viewportColumns}}
{{ >lesionMeasurementContainer studies=studies activeViewport=activeViewport}}
<div id="upperHalf">
{{ >hidingPanel studies=studies activeViewport=activeViewport}}
{{ >viewerMain studies=studies activeViewport=activeViewport viewportRows=viewportRows viewportColumns=viewportColumns}}
</div>
{{ >lesionTable studies=studies activeViewport=activeViewport viewportRows=viewportRows viewportColumns=viewportColumns}}
</div>
</template>

View File

@ -2,6 +2,5 @@
<div class="viewerMain">
{{ >toolbar toolbarOptions=toolbarOptions activeViewport=activeViewport viewportRows=viewportRows viewportColumns=viewportColumns}}
{{ >imageViewerViewports studies=studies activeViewport=activeViewport viewportRows=viewportRows viewportColumns=viewportColumns}}
{{ >lesionTableContainer studies=studies activeViewport=activeViewport}}
</div>
</template>

View File

@ -72,7 +72,7 @@ Template.viewerMain.helpers({
toolbarOptions.buttonData = buttonData;
toolbarOptions.includePlayClipButton = true;
toolbarOptions.includeLayoutButton = false;
toolbarOptions.includeLayoutButton = true;
return toolbarOptions;
}
});

View File

@ -1,8 +1,4 @@
.viewerMain
width: 64%;
width: calc(100% - 120px)
height: 100%
float: left
#imageViewerViewports
height: calc(75% - 30px)
width: 100%
float: left

View File

@ -828,6 +828,14 @@ if (typeof cornerstoneTools === 'undefined') {
data.active = !data.active;
imageNeedsUpdate = true;
}
//TODO: ayselafsar
//Check hover event for lesion tool text
if (mouseToolInterface.toolType === "lesion") {
if ( mouseToolInterface.pointNearToolForText(eventData.element, data, coords) && !data.active) {
data.active = !data.active;
}
}
}
// Handle activation status changed, redraw the image
@ -892,6 +900,19 @@ if (typeof cornerstoneTools === 'undefined') {
}
}
}
//TODO: ayselafsar: Add check statement if mouse down location is on text callout. If so, call moveTextCallout function
if(toolData !== undefined && mouseToolInterface.pointNearToolForText !== undefined) {
for(i=0; i < toolData.data.length; i++) {
data = toolData.data[i];
if(mouseToolInterface.pointNearToolForText(eventData.element, data, coords)) {
$(eventData.element).off('CornerstoneToolsMouseMove', mouseMoveCallback);
cornerstoneTools.moveTextHandles(e, data, toolData, true);
e.stopImmediatePropagation();
return false;
}
}
}
}
}
///////// END DEACTIVE TOOL ///////
@ -6052,8 +6073,94 @@ if (typeof cornerstoneTools === 'undefined') {
return true;
}
//TODO:moveTextHandles-ayselafsar
function moveTextHandles(e, data, toolData, deleteIfHandleOutsideImage, preventHandleOutsideImage)
{
var mouseEventData = e;
var element = mouseEventData.element;
function mouseDragCallback(e, eventData)
{
for(var property in data.handles) {
var handle = data.linkedTextCoords[property];
handle.x += eventData.deltaPoints.image.x;
handle.y += eventData.deltaPoints.image.y;
if (preventHandleOutsideImage)
{
if (handle.x < 0)
{
handle.x = 0;
}
if (handle.x > eventData.image.width)
{
handle.x = eventData.image.width;
}
if (handle.y < 0)
{
handle.y = 0;
}
if (handle.y > eventData.image.height)
{
handle.y = eventData.image.height;
}
}
}
cornerstone.updateImage(element);
return false; // false = cases jquery to preventDefault() and stopPropagation() this event
}
$(element).on("CornerstoneToolsMouseDrag", mouseDragCallback);
function mouseUpCallback(e, eventData) {
data.moving = false;
$(element).off('CornerstoneToolsMouseDrag', mouseDragCallback);
$(element).off('CornerstoneToolsMouseUp', mouseUpCallback);
// If any handle is outside the image, delete the tool data
if(deleteIfHandleOutsideImage === true) {
var image = eventData.image;//.getEnabledElement(element).image;
var handleOutsideImage = false;
var rect = {
top: 0,
left: 0,
width: image.width,
height: image.height
};
for(var property in data.handles) {
var handle = data.handles[property];
if(cornerstoneMath.point.insideRect(handle, rect) === false)
{
handleOutsideImage = true;
}
}
if(handleOutsideImage)
{
// find this tool data
var indexOfData = -1;
for(var i = 0; i < toolData.data.length; i++) {
if(toolData.data[i] === data)
{
indexOfData = i;
}
}
if(indexOfData !== -1) {
toolData.data.splice(indexOfData, 1);
}
}
}
cornerstone.updateImage(element);
}
$(element).on("CornerstoneToolsMouseUp",mouseUpCallback);
return true;
}
// module/private exports
cornerstoneTools.moveAllHandles = moveAllHandles;
cornerstoneTools.moveTextHandles = moveTextHandles;
})($, cornerstone, cornerstoneMath, cornerstoneTools);

View File

@ -24,7 +24,7 @@ function setValidator(measurements) {
// Or a remote call
function remoteSetValidator(measurements) {
var deferred = $.Deferred;
var deferred = $.Deferred();
var result = {
isValid: true,
@ -33,8 +33,8 @@ function remoteSetValidator(measurements) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var response = JSON.parse(xhr.response);
if (response.isValid) {
deferred.resolve(xhr.responseText);

View File

@ -22,7 +22,7 @@ var cornerstoneTools = (function ($, cornerstone, cornerstoneMath, cornerstoneTo
//Listens LesionToolModified event and calls measurementModified function when lesion measurement is changed or updated.
$(element).on("LesionToolModified", measurementModified);
$(element).trigger("LesionMeasurementCreated", mouseEventData);
$(element).trigger("LesionMeasurementCreated");
// create the measurement data for this tool with the end handle activated
var measurementData = {

View File

@ -0,0 +1,31 @@
Template.lesionDialog.onRendered(function () {
// Listen lesionMeaurementCreated Event and when this event is triggered, show lesionLocationDialog Box
$(document).on("lesionMeasurementCreated",function(e,eventCaller,data){
var element = data.element;
var tabId = data.tabId;
var viewports = $("#content"+tabId).find(".imageViewerViewport");
var viewportIndex = $(viewports).index($(element));
data.viewportIndex = viewportIndex;
data.totalViewportCount = viewports.length;
//Set Lesion Table Data to insert into lesion table
setLesionTableData(data);
// Check popup will shown or not
var returnVal = lesionNumberIsAdded(data);
if(!returnVal.isFound) {
if( !Session.get("lesionLocationSelected") ) {
$("#modal-dialog-container").css({
"top": eventCaller.pageY,
"left": eventCaller.pageX
});
$("#lesionDialog").modal("show");
}
} else {
// If lesionNumber is added before:
data.rowIndex = returnVal.rowIndex;
$(document).trigger("addLesionToExistedRow",data);
}
});
});

View File

@ -28,7 +28,7 @@ Template.lesionLocationDialog.events({
'change select#selectLesionLocation': function (e) {
var el = $(e.target);
var selectedLocationIndex = el.val();
var selectedLocationIndex = el.val()
if(selectedLocationIndex !== "-1"){
var locationObj = lesionLocationsArray[selectedLocationIndex];

View File

@ -0,0 +1,24 @@
<template name="lesionTable">
<div id="lesionTableContainer">
<table class="table table-bordered lesionTable" id="tblLesion">
<thead>
<tr>
<th id="thNumber">Lesion #</th>
<th id="thTarget">Target</th>
<th id="thLocation">Location</th>
<!--Each time point name as a column-->
{{ #each timepointNames }}
{{ >lesionTableTimepointHeader }}
{{ /each }}
</tr>
</thead>
<tbody>
{{ #each measurement }}
{{ >lesionTableRow }}
{{ /each }}
<!--Each measurement as row-->
<!--Each time point as a column-->
</tbody>
</table>
</div>
</template>

View File

@ -0,0 +1,187 @@
measurements = new Meteor.Collection(null);
var test = {
lesionNumber: 1,
isTarget: true,
location: 'Brain',
timepoints: {
"now": {
imageId: "blah",
timepointUid: "timepointX",
date: 2010,
isDirty: true,
longestDiameter: 5
},
"earlier": {
imageId: "blah2",
timepointUid: "timepointy",
date: 2010,
isDirty: true,
longestDiameter: 8
}
}
};
measurements.insert(test);
Template.lesionTable.helpers({
'measurement': function() {
return measurements.find();
},
'timepointNames': function() {
return [
{name: 'now'},
{name: 'earlier'}
];
}
});
/*var lesionTableData;
setLesionTableData = function (data) {
lesionTableData = data;
};
getLesionTableData = function () {
return lesionTableData;
};
lesionNumberIsAdded = function(data) {
var tabId = data.tabId;
var returnValue = {isFound: false, rowIndex : -1};
$('#content'+tabId+' table tbody tr td.lesionNumber').each( function(){
console.log($(this).text());
var lesionNumber = parseInt($(this).text());
if(lesionNumber == data.lesionNumber) {
var $tr = $(this).closest('tr');
var rowIndex = $tr.index();
returnValue.rowIndex = rowIndex;
returnValue.isFound = true;
}
});
return returnValue;
};
returnTblStr = function (obj) {
// Get count of lds
var tabId = obj.tabId;
var lds = $("#content"+tabId).find(".lesionTable th.ld");
var rowStr = '<tr style="background-color: #b3b3b3;">' +
'<td style="text-align:center;"><button type="button" class="btnRemove fa fa-times fa-lg" title="Remove"></button></td>' +
'<td style="text-align:center;" class="lesionNumber">'+obj.lesionNumber+'</td>' +
'<td style="text-align:center;">Y</td>';
// Add measurement to right column
if(obj.totalViewportCount) {
for(var i=0; i< lds.length; i++) {
if(i === obj.viewportIndex) {
rowStr += '<td>'+obj.lesionLocationObj.location+'</td><td id='+obj.lineIndex+' class="lesion" style="text-align: left;">'+obj.lesions+'</td>';
}else{
rowStr += '<td>'+obj.lesionLocationObj.location+'</td><td class="lesion" style="text-align: left;"></td>';
}
}
}
rowStr += '</tr>';
return rowStr;
};
//Link lesionLocationSelected event
$(document).on("lesionLocationSelected",function(event,data ){
var lesionData = getLesionTableData();
lesionData.lesionLocationObj = data;
var tabId = lesionData.tabId;
//var el_index = lesionData.viewportIndex;
var tableEl = $("#content"+tabId).find(".lesionTable");
var tblStr = returnTblStr(lesionData);
$(tableEl).append(tblStr);
});
//Link addLesionToExistedRow event
$(document).on("addLesionToExistedRow",function(event,data ){
// Get count of lds
var tabId = data.tabId;
var lds = $("#content"+tabId).find(".lesionTable th.ld");
// Add measurement to right column
for(var i=0; i< lds.length; i++) {
if(i === data.viewportIndex) {
var rowIndex = data.rowIndex + 1;
var row = $("#content"+tabId).find(".lesionTable tr").eq(rowIndex);
var cell = $(row).find("td.lesion").eq(data.viewportIndex);
$(cell).attr("id", data.lineIndex);
$(cell).html(data.lesions);
}
}
});
$(document).on("lesionTextChanged", function(event, data){
var cellId = data.index;
$("td#"+cellId).html(data.measurementText);
});
Template.lesionTable.onRendered( function () {
// TODO: Set lesion table as hiding-panel
console.log(this);
var template = this;
var tabId = this.data.tabId;
var viewports = $("#content"+tabId).find(".imageViewerViewport");
var lesionTable = $("#content"+tabId).find(".lesionTable");
var viewportCount = viewports.length;
var lesionTableWidth = $(lesionTable).width();
var viewportWidth = viewports.width();
var ldColumnRatio = viewportWidth / lesionTableWidth * 100;
// Add LD column as viewportCount
// Set lesion table columns width
if(viewportCount > 0) {
if(viewportCount == 1) {
$('#content'+tabId+' thead tr').append( $('<th />', {text : 'Location', width: ldColumnRatio/2+'%', class:'thLocation'}) )
$('#content'+tabId+' thead tr').append( $('<th />', {text : 'LD', width: ldColumnRatio/2+'%', class:'ld'}) )
} else if(viewportCount == 2) {
for(var i = 0; i< viewportCount; i++) {
$('#content'+tabId+' thead tr').append( $('<th />', {text : 'Location'+i, width: ldColumnRatio/2+'%', class:'thLocation'}) )
$('#content'+tabId+' thead tr').append( $('<th />', {text : 'LD'+i, width: ldColumnRatio/2+'%', class:'ld'}) )
}
} else if(viewportCount > 2) {
// TODO: Set when viewport count is bigger than 2
}
}
// TODO: When layout is changed, add and calculate new columns for measurement
});
Template.lesionTable.events({
'click button.btnRemove': function (e) {
var el = $(e.target);
},
'click table tbody tr': function(e) {
console.log(this);
var row = e.currentTarget;
var lesionCells = $(row).find("td.lesion");
for(var i = 0; i< lesionCells.length; i++) {
var cell = lesionCells[i];
var idAttr = $(cell).attr("id");
if(idAttr != undefined) {
// TODO: Create eventObject and trigger LesionToolModified event
var viewports = $(".imageViewerViewport");
var eventObject = {
enabledElement: cornerstone.getEnabledElement(viewports[0]),
lineIndex: parseInt(idAttr),
type: "active"
};
$(viewports[0]).trigger("LesionToolModified", eventObject);
}
}
}
});*/

View File

@ -0,0 +1,44 @@
#lesionTableContainer
width: 100%
height: 25%
table.lesionTable
thead
th
background-color: #424242
font-style: italic
color:white
text-align: center
height: 15px
width: 20px
table.lesionTable > thead > tr > th {
padding: 4px;
margin: 0;
height: 25px;
line-height: 15px;
}
table.lesionTable > tbody > tr > td {
padding: 4px;
margin: 0;
height: 25px;
line-height: 15px;
}
table.lesionTable tbody tr:hover{
background-color: #d1d1d1;
}
table.lesionTable tbody tr{
background-color: #b3b3b3;
color: #424242;
line-height: 14px;
}
.btnRemove{
border: none;
outline:none;
background-color: transparent;
}

View File

@ -0,0 +1,11 @@
<template name="lesionTableRow">
<tr>
<th class='lesionNumber'>{{lesionNumber}}</th>
<th class='target'>{{isTarget}}</th>
<th class='location'>{{location}}</th>
<!--Each time point as a column-->
{{ #each timepoints}}
{{ >lesionTableTimepointCell}}
{{ /each }}
</tr>
</template>

View File

@ -0,0 +1,10 @@
Template.lesionTableRow.helpers({
'timepoints': function() {
var array = [];
var timepoints = this.timepoints;
Object.keys(timepoints).forEach(function(key) {
array.push(timepoints[key]);
});
return array;
},
});

View File

@ -0,0 +1,3 @@
<template name="lesionTableTimepointCell">
<td>{{longestDiameter}}</td>
</template>

View File

@ -0,0 +1,3 @@
<template name="lesionTableTimepointHeader">
<th>{{name}}</th>
</template>

View File

@ -0,0 +1,35 @@
Package.describe({
name: "lesiontracker",
summary: "OHIF Lesion Tracker Tools",
version: '0.0.1'
});
Package.onUse(function (api) {
api.versionsFrom('1.2.0.2');
api.use('standard-app-packages');
api.use('jquery');
api.use('stylus');
// Our custom package
api.use('cornerstone');
api.addFiles('compatibility/lesionTool.js', 'client', {bare: true});
api.addFiles('components/lesionDialog/lesionDialog.html', 'client');
api.addFiles('components/lesionDialog/lesionDialog.js', 'client');
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.html', 'client');
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.js', 'client');
api.addFiles('components/lesionTable/lesionTable.html', 'client');
api.addFiles('components/lesionTable/lesionTable.styl', 'client');
api.addFiles('components/lesionTable/lesionTable.js', 'client');
api.addFiles('components/lesionTableRow/lesionTableRow.html', 'client');
api.addFiles('components/lesionTableRow/lesionTableRow.js', 'client');
api.addFiles('components/lesionTableTimepointCell/lesionTableTimepointCell.html', 'client');
api.addFiles('components/lesionTableTimepointHeader/lesionTableTimepointHeader.html', 'client');
});

View File

@ -1,5 +1,5 @@
.hidingPanel
width: 12%
width: 120px
height: 100%
padding-top: 35px
position: relative

View File

@ -22,6 +22,9 @@ Package.onUse(function (api) {
api.addFiles('components/basic/login/login.html', 'client');
api.addFiles('components/basic/notFound/notFound.html', 'client');
api.addFiles('components/basic/hidingPanel/hidingPanel.html', 'client');
api.addFiles('components/basic/hidingPanel/hidingPanel.styl', 'client');
// Study Browser components
api.addFiles('components/studyBrowser/studyBrowser/studyBrowser.html', 'client');
api.addFiles('components/studyBrowser/studyBrowser/studyBrowser.js', 'client');