Merged LesionTracker and OHIF Viewer, refactored out common components
This commit is contained in:
1 parent
34adbe3fbc
commit
b774c22593
144 files changed
+27820
No files matched your search
@@ -0,0 +1,12 @@
|
||||
# This file contains information which helps Meteor properly upgrade your
|
||||
# app when you run 'meteor update'. You should check it into version control
|
||||
# with your project.
|
||||
|
||||
notices-for-0.9.0
|
||||
notices-for-0.9.1
|
||||
0.9.4-platform-file
|
||||
notices-for-facebook-graph-api-2
|
||||
1.2.0-standard-minifiers-package
|
||||
1.2.0-meteor-platform-split
|
||||
1.2.0-cordova-changes
|
||||
1.2.0-breaking-changes
|
||||
@@ -0,0 +1 @@
|
||||
local
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file contains a token that is unique to your project.
|
||||
# Check it into your repository along with the rest of this directory.
|
||||
# It can be used for purposes such as:
|
||||
# - ensuring you don't accidentally deploy one app on top of another
|
||||
# - providing package authors with aggregated statistics
|
||||
|
||||
1q3vtk41m2yk4k1rqj08l
|
||||
@@ -0,0 +1,34 @@
|
||||
# Meteor packages used by this project, one per line.
|
||||
# Check this file (and the other files in this directory) into your repository.
|
||||
#
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-base # Packages every Meteor app needs to have
|
||||
mobile-experience # Packages for a great mobile UX
|
||||
mongo # The database Meteor supports right now
|
||||
blaze-html-templates # Compile .html files into Meteor Blaze views
|
||||
session # Client-side reactive dictionary for your app
|
||||
jquery # Helpful client-side library
|
||||
tracker # Meteor's client-side reactive programming library
|
||||
|
||||
standard-minifiers # JS/CSS minifiers run for production mode
|
||||
es5-shim # ECMAScript 5 compatibility for older browsers.
|
||||
ecmascript # Enable ECMAScript2015+ syntax in app code
|
||||
|
||||
autopublish # Publish all data to the clients (for prototyping)
|
||||
insecure # Allow all DB writes from clients (for prototyping)
|
||||
cornerstone
|
||||
worklist
|
||||
viewerbase
|
||||
dicomweb
|
||||
accounts-password
|
||||
|
||||
ian:accounts-ui-bootstrap-3
|
||||
iron:router
|
||||
twbs:bootstrap
|
||||
http
|
||||
arsnebula:reactive-promise
|
||||
promise
|
||||
stylus
|
||||
fortawesome:fontawesome
|
||||
@@ -0,0 +1,2 @@
|
||||
server
|
||||
browser
|
||||
@@ -0,0 +1 @@
|
||||
METEOR@1.2.0.2
|
||||
@@ -0,0 +1,96 @@
|
||||
accounts-base@1.2.1
|
||||
accounts-password@1.1.3
|
||||
anti:i18n@0.4.3
|
||||
arsnebula:reactive-promise@0.9.1
|
||||
autopublish@1.0.4
|
||||
autoupdate@1.2.3
|
||||
babel-compiler@5.8.24_1
|
||||
babel-runtime@0.1.4
|
||||
base64@1.0.4
|
||||
binary-heap@1.0.4
|
||||
blaze@2.1.3
|
||||
blaze-html-templates@1.0.1
|
||||
blaze-tools@1.0.4
|
||||
boilerplate-generator@1.0.4
|
||||
caching-compiler@1.0.0
|
||||
caching-html-compiler@1.0.2
|
||||
callback-hook@1.0.4
|
||||
check@1.0.6
|
||||
cornerstone@0.0.1
|
||||
ddp@1.2.2
|
||||
ddp-client@1.2.1
|
||||
ddp-common@1.2.1
|
||||
ddp-rate-limiter@1.0.0
|
||||
ddp-server@1.2.1
|
||||
deps@1.0.9
|
||||
dicomweb@0.0.1
|
||||
diff-sequence@1.0.1
|
||||
ecmascript@0.1.5
|
||||
ecmascript-collections@0.1.6
|
||||
ejson@1.0.7
|
||||
email@1.0.7
|
||||
es5-shim@4.1.13
|
||||
fastclick@1.0.7
|
||||
fortawesome:fontawesome@4.4.0
|
||||
geojson-utils@1.0.4
|
||||
hot-code-push@1.0.0
|
||||
html-tools@1.0.5
|
||||
htmljs@1.0.5
|
||||
http@1.1.1
|
||||
ian:accounts-ui-bootstrap-3@1.2.82
|
||||
id-map@1.0.4
|
||||
insecure@1.0.4
|
||||
iron:controller@1.0.12
|
||||
iron:core@1.0.11
|
||||
iron:dynamic-template@1.0.12
|
||||
iron:layout@1.0.12
|
||||
iron:location@1.0.11
|
||||
iron:middleware-stack@1.0.11
|
||||
iron:router@1.0.12
|
||||
iron:url@1.0.11
|
||||
jquery@1.11.4
|
||||
launch-screen@1.0.4
|
||||
livedata@1.0.15
|
||||
localstorage@1.0.5
|
||||
logging@1.0.8
|
||||
meteor@1.1.9
|
||||
meteor-base@1.0.1
|
||||
meteor-platform@1.2.3
|
||||
minifiers@1.1.7
|
||||
minimongo@1.0.10
|
||||
mobile-experience@1.0.1
|
||||
mobile-status-bar@1.0.6
|
||||
mongo@1.1.2
|
||||
mongo-id@1.0.1
|
||||
npm-bcrypt@0.7.8_2
|
||||
npm-mongo@1.4.39_1
|
||||
observe-sequence@1.0.7
|
||||
ordered-dict@1.0.4
|
||||
promise@0.5.0
|
||||
random@1.0.4
|
||||
rate-limit@1.0.0
|
||||
reactive-dict@1.1.2
|
||||
reactive-var@1.0.6
|
||||
reload@1.1.4
|
||||
retry@1.0.4
|
||||
routepolicy@1.0.6
|
||||
service-configuration@1.0.5
|
||||
session@1.1.1
|
||||
sha@1.0.4
|
||||
spacebars@1.0.7
|
||||
spacebars-compiler@1.0.7
|
||||
srp@1.0.4
|
||||
standard-app-packages@1.0.6
|
||||
standard-minifiers@1.0.1
|
||||
stylus@2.511.0_2
|
||||
templating@1.1.4
|
||||
templating-tools@1.0.0
|
||||
tracker@1.0.9
|
||||
twbs:bootstrap@3.3.5
|
||||
ui@1.0.8
|
||||
underscore@1.0.4
|
||||
url@1.0.5
|
||||
viewerbase@0.0.1
|
||||
webapp@1.2.2
|
||||
webapp-hashing@1.0.5
|
||||
worklist@0.0.1
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
echo "Starting Meteor server..."
|
||||
PACKAGE_DIRS="../Packages" meteor --settings ../config/localhostOrthanc.json
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
PACKAGE_DIRS="../Packages" meteor --settings ../config/medicalConnections.json
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
PACKAGE_DIRS="../Packages" meteor --settings ../config/medkenOrthanc.json
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
PACKAGE_DIRS="../Packages" meteor --settings ../config/siimDCM4CHEE.json
|
||||
@@ -0,0 +1,33 @@
|
||||
//Collapse the container
|
||||
function collapseContainer ( container ) {
|
||||
container.toggleClass("collapseHorizontal");
|
||||
}
|
||||
|
||||
//function add collapse button
|
||||
function addButtonCollapse ( container ) {
|
||||
var btnCollapse = document.createElement("button");
|
||||
btnCollapse.innerHTML = ">";
|
||||
btnCollapse.classList.add('btnCollapse');
|
||||
|
||||
btnCollapse.onclick = function() { // Note this is a function
|
||||
collapseContainer(container);
|
||||
};
|
||||
container.append(btnCollapse);
|
||||
}
|
||||
|
||||
$.fn.dockingContainer = function(options) {
|
||||
var self = this;
|
||||
var opts = $.extend( {}, $.fn.dockingContainer.defaults, options);
|
||||
|
||||
//Set container class
|
||||
this.addClass("dockingContainer");
|
||||
|
||||
//Add btnCollapse
|
||||
addButtonCollapse(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
//Defaults
|
||||
$.fn.dockingContainer.defaults = {
|
||||
background: "black"
|
||||
};
|
||||
@@ -0,0 +1,285 @@
|
||||
var lineIndex = 0; //This holds drawn line index
|
||||
var cornerstoneTools = (function ($, cornerstone, cornerstoneMath, cornerstoneTools) {
|
||||
|
||||
"use strict";
|
||||
|
||||
if(cornerstoneTools === undefined) {
|
||||
cornerstoneTools = {};
|
||||
}
|
||||
|
||||
var toolType = "lesion";
|
||||
|
||||
///////// BEGIN ACTIVE TOOL ///////
|
||||
function createNewMeasurement(mouseEventData)
|
||||
{
|
||||
var element = mouseEventData.element;
|
||||
var lesionCounter = "";
|
||||
|
||||
//setting name of lesion
|
||||
$(element).on("LesionNameSet", function(e,counter){
|
||||
lesionCounter = counter;
|
||||
});
|
||||
|
||||
//Listens LesionToolModified event and calls measurementModified function when lesion measurement is changed or updated.
|
||||
$(element).on("LesionToolModified", measurementModified);
|
||||
$(element).trigger("LesionMeasurementCreated");
|
||||
|
||||
// create the measurement data for this tool with the end handle activated
|
||||
var measurementData = {
|
||||
visible : true,
|
||||
active : true,
|
||||
handles : {
|
||||
start : {
|
||||
x : mouseEventData.currentPoints.image.x,
|
||||
y : mouseEventData.currentPoints.image.y,
|
||||
highlight: true,
|
||||
active: false
|
||||
},
|
||||
end: {
|
||||
x : mouseEventData.currentPoints.image.x,
|
||||
y : mouseEventData.currentPoints.image.y,
|
||||
highlight: true,
|
||||
active: true
|
||||
}
|
||||
},
|
||||
index: lineIndex,
|
||||
measurementText: "",
|
||||
linkedTextCoords: {
|
||||
start : {
|
||||
x : mouseEventData.currentPoints.image.x,
|
||||
y : mouseEventData.currentPoints.image.y,
|
||||
highlight: true,
|
||||
active: false
|
||||
},
|
||||
end: {
|
||||
x : mouseEventData.currentPoints.image.x,
|
||||
y : mouseEventData.currentPoints.image.y,
|
||||
highlight: true,
|
||||
active: true
|
||||
},
|
||||
init: false
|
||||
},
|
||||
lesionName: "Target "+lesionCounter,
|
||||
isDeleted: false,
|
||||
lineNumber:"" //Indicates line number on image
|
||||
};
|
||||
lineIndex++;
|
||||
return measurementData;
|
||||
}
|
||||
///////// END ACTIVE TOOL ///////
|
||||
|
||||
function pointNearTool(element, data, coords)
|
||||
{
|
||||
var lineSegment = {
|
||||
start: cornerstone.pixelToCanvas(element, data.handles.start), end: cornerstone.pixelToCanvas(element, data.handles.end)
|
||||
};
|
||||
var distanceToPoint = cornerstoneMath.lineSegment.distanceToPoint(lineSegment, coords);
|
||||
return (distanceToPoint < 25);
|
||||
}
|
||||
|
||||
function pointNearToolForText(element, data, coords) {
|
||||
var lineSegment = {
|
||||
start: cornerstone.pixelToCanvas(element, data.linkedTextCoords.start), end: cornerstone.pixelToCanvas(element, data.linkedTextCoords.end)
|
||||
};
|
||||
|
||||
var distanceToPoint = cornerstoneMath.lineSegment.distanceToPoint(lineSegment, coords);
|
||||
return (distanceToPoint < 30);
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////// BEGIN IMAGE RENDERING ///////
|
||||
function onImageRendered(e, eventData) {
|
||||
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
var color;
|
||||
var lineWidth = cornerstoneTools.toolStyle.getToolWidth();
|
||||
var font = cornerstoneTools.textStyle.getFont();
|
||||
var config = cornerstoneTools.length.getConfiguration();
|
||||
|
||||
for (var i = 0; i < toolData.data.length; i++) {
|
||||
context.save();
|
||||
// configurable shadow
|
||||
if (config && config.shadow) {
|
||||
context.shadowColor = '#000000';
|
||||
context.shadowOffsetX = +1;
|
||||
context.shadowOffsetY = +1;
|
||||
}
|
||||
|
||||
var data = toolData.data[i];
|
||||
if (data.active) {
|
||||
color = cornerstoneTools.toolColors.getActiveColor();
|
||||
} else {
|
||||
color = cornerstoneTools.toolColors.getToolColor();
|
||||
}
|
||||
|
||||
// draw the line
|
||||
var handleStartCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.start);
|
||||
var handleEndCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.end);
|
||||
|
||||
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);
|
||||
|
||||
//Set coordinates of text
|
||||
var linkedTextStartCanvas = cornerstone.pixelToCanvas(eventData.element, data.linkedTextCoords.start);
|
||||
var linkedTextEndCanvas = cornerstone.pixelToCanvas(eventData.element, data.linkedTextCoords.end);
|
||||
if(!data.linkedTextCoords.init){
|
||||
data.linkedTextCoords.start.x = data.handles.start.x + 50;
|
||||
data.linkedTextCoords.start.y = data.handles.start.y + 40;
|
||||
linkedTextStartCanvas = cornerstone.pixelToCanvas(eventData.element, data.linkedTextCoords.start);
|
||||
|
||||
//Set end point of linkedTextCoords
|
||||
data.linkedTextCoords.end.x = data.linkedTextCoords.start.x + 50;
|
||||
data.linkedTextCoords.end.y = data.linkedTextCoords.start.y + 30;
|
||||
linkedTextEndCanvas = cornerstone.pixelToCanvas(eventData.element, data.linkedTextCoords.end);
|
||||
|
||||
//initialized coordinates of text
|
||||
data.linkedTextCoords.init = true;
|
||||
}
|
||||
|
||||
//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(linkedTextStartCanvas.x + 20, linkedTextStartCanvas.y + 20);
|
||||
context.stroke();
|
||||
|
||||
// Draw the text
|
||||
context.fillStyle = color;
|
||||
context.font = font;
|
||||
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 textCoords = {
|
||||
x: linkedTextStartCanvas.x, y: linkedTextStartCanvas.y
|
||||
};
|
||||
|
||||
cornerstoneTools.drawTextBox(context, data.lesionName, textCoords.x, textCoords.y, color);
|
||||
cornerstoneTools.drawTextBox(context, text, textCoords.x, textCoords.y + 20, color);
|
||||
|
||||
//Set measurement text to show lesion table
|
||||
data.measurementText = length.toFixed(2);
|
||||
$(eventData.enabledElement.element).trigger("LesionTextChanged",data);
|
||||
|
||||
context.restore();
|
||||
}
|
||||
|
||||
}
|
||||
///////// END IMAGE RENDERING ///////
|
||||
|
||||
//This function is called from cornerstone-viewport.html and updates lesion measurement and makes the lesion active
|
||||
function measurementModified(e, eventObject){
|
||||
var start = new Date();
|
||||
|
||||
var enabledElement = eventObject.enabledElement;
|
||||
var lineIndex = eventObject.lineIndex;
|
||||
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 === undefined) {
|
||||
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.index === eventObject.lineIndex && eventObject.type !== "active") {
|
||||
data.visible = false;
|
||||
deletedDataIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (deletedDataIndex >= 0 && deletedDataIndex < toolData.data.length) {
|
||||
toolData.data.splice(deletedDataIndex, 1);
|
||||
}
|
||||
} else {
|
||||
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.index === eventObject.lineIndex && eventObject.type === "active") {
|
||||
data.active = true;
|
||||
} else{
|
||||
data.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enabledElement.image.render(enabledElement, true);
|
||||
|
||||
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,
|
||||
lineIndex : lineIndex,
|
||||
type : type //Holds image will be deleted or active
|
||||
};
|
||||
|
||||
enabledElement.invalid = false;
|
||||
|
||||
onImageRendered(e, eventData);
|
||||
}
|
||||
|
||||
// module exports
|
||||
cornerstoneTools.lesion = cornerstoneTools.mouseButtonTool({
|
||||
createNewMeasurement : createNewMeasurement,
|
||||
onImageRendered: onImageRendered,
|
||||
pointNearTool : pointNearTool,
|
||||
pointNearToolForText: pointNearToolForText,
|
||||
toolType : toolType
|
||||
});
|
||||
cornerstoneTools.lesionTouch = cornerstoneTools.touchTool({
|
||||
createNewMeasurement: createNewMeasurement,
|
||||
onImageRendered: onImageRendered,
|
||||
pointNearTool: pointNearTool,
|
||||
pointNearToolForText: pointNearToolForText,
|
||||
toolType: toolType
|
||||
});
|
||||
return cornerstoneTools;
|
||||
}($, cornerstone, cornerstoneMath, cornerstoneTools));
|
||||
@@ -0,0 +1,15 @@
|
||||
//Holds functions to help managing tabs
|
||||
|
||||
//Returns activeTabId
|
||||
function activeTabId() {
|
||||
var activeTab = Session.get("activeTabId");
|
||||
return activeTab;
|
||||
}
|
||||
|
||||
//Returns activeTabContentId
|
||||
function activeTabContentId () {
|
||||
var activeTabId = activeTabId();
|
||||
var splitTabId = activeTabId.split("tab");
|
||||
var contentId = "content"+splitTabId[1];
|
||||
return contentId;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<template name="hidingPanel">
|
||||
<div class="hidingPanel">
|
||||
{{> studyBrowser}}
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,9 @@
|
||||
.hidingPanel
|
||||
width: 12%
|
||||
height: 100%
|
||||
margin-top: 35px
|
||||
position: relative
|
||||
float: left
|
||||
overflow: auto
|
||||
background-color: blue
|
||||
color: black
|
||||
@@ -0,0 +1,48 @@
|
||||
.toolbar {
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#toolbar-group button {
|
||||
text-align: center;
|
||||
margin-top: 2px;
|
||||
margin-right: 3px;
|
||||
margin-left: 3px;
|
||||
color: #ffffff;
|
||||
background-color: black;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
#toolbar-group button > span {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
left: 9px;
|
||||
right: 9px;
|
||||
bottom: 9px;
|
||||
}
|
||||
|
||||
|
||||
#toolbar-group .btn:hover {
|
||||
border-width: 3px;
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
}
|
||||
#toolbar-group .btn:focus, .btn:active {
|
||||
outline: 0 !important;
|
||||
border-width: 5px;
|
||||
background-color: transparent;
|
||||
color:white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#toolbar-group .btn:focus > span{
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
bottom: 6px;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<template name="toolbar">
|
||||
<div id="toolbar" class="toolbar">
|
||||
<div id="toolbar-group" class="btn-group">
|
||||
<!-- WW/WL -->
|
||||
<button id="wwwc" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="WW/WC"><span class="fa fa-sun-o"></span></button>
|
||||
<!-- Invert -->
|
||||
<button id="invert" type="button" class="imageViewerCommand btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Invert"><span class="fa fa-adjust"></span></button>
|
||||
<!-- Zoom -->
|
||||
<button id="zoom" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Zoom"><span class="fa fa-search"></span></button>
|
||||
<!-- Pan -->
|
||||
<button id="pan" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Pan"><span class="fa fa-arrows"></span></button>
|
||||
<!-- Stack scroll -->
|
||||
<button id="stackScroll" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Stack Scroll"><span class="fa fa-bars"></span></button>
|
||||
<!-- Play clip -->
|
||||
<button id="playClip" type="button" class="imageViewerCommand btn btn-sm btn-default" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Play/Stop Clip">
|
||||
{{ #if isPlaying }}
|
||||
<span class="fa fa-stop"></span>
|
||||
{{ else }}
|
||||
<span class="fa fa-play"></span>
|
||||
{{ /if }}
|
||||
</button>
|
||||
<!-- Angle measurement -->
|
||||
<!--<button id="angle" type="button" class="imageViewerTool btn btn-sm btn-default" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Angle Measurement"><span class="fa fa-angle-left"></span></button>-->
|
||||
<!-- Pixel probe -->
|
||||
<button id="dragProbe" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Pixel Probe"><span class="fa fa-dot-circle-o"></span></button>
|
||||
<!-- Length measurement -->
|
||||
<button id="length" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Length Measurement"><span class="fa fa-arrows-v"></span></button>
|
||||
<!-- Elliptical ROI -->
|
||||
<button id="ellipticalRoi" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Elliptical ROI"><span class="fa fa-circle-o"></span></button>
|
||||
<!-- Rectangle ROI -->
|
||||
<button id="rectangleRoi" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Rectangle ROI"><span class="fa fa-square-o"></span></button>
|
||||
<!-- Lesion Tool -->
|
||||
<button id="lesion" type="button" class="imageViewerTool btn btn-sm btn-toolbar" data-container="body" data-toggle="tooltip" data-placement="bottom" title="Lesion Tool"><span class="fa fa-arrows-v"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
Template.toolbar.events({
|
||||
'click .imageViewerTool': function(e) {
|
||||
var tool = e.currentTarget.id;
|
||||
console.log('Setting active tool to: ' + tool);
|
||||
toolManager.setActiveTool(tool);
|
||||
},
|
||||
'click .imageViewerCommand': function(e) {
|
||||
var command = e.currentTarget.id;
|
||||
if (!OHIF.viewer.functionList.hasOwnProperty(command)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO = Add support for active viewports
|
||||
//var element = getActiveViewportElement();
|
||||
$('.imageViewer').each(function() {
|
||||
var element = this;
|
||||
OHIF.viewer.functionList[command](element);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Template.toolbar.onRendered(function() {
|
||||
var tooltipButtons = $('[data-toggle="tooltip"]');
|
||||
tooltipButtons.tooltip(OHIF.viewer.tooltipConfig);
|
||||
|
||||
// Enable tooltips for the layout button
|
||||
var extraTooltipButtons = $('[rel="tooltip"]');
|
||||
extraTooltipButtons.tooltip(OHIF.viewer.tooltipConfig);
|
||||
|
||||
toolManager.addTool('lesion', {
|
||||
mouse: cornerstoneTools.lesion,
|
||||
touch: cornerstoneTools.lesionTouch
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
.viewer{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: black;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<template name="viewer">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
</head>
|
||||
<div id="viewer" class="viewer">
|
||||
{{ >hidingPanel }}
|
||||
{{ >viewerMain }}
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,89 @@
|
||||
OHIF = {
|
||||
viewer: {}
|
||||
};
|
||||
|
||||
OHIF.viewer.imageViewerLoadedSeriesDictionary = {};
|
||||
OHIF.viewer.imageViewerCurrentImageIdIndexDictionary = {};
|
||||
OHIF.viewer.loadIndicatorDelay = 3000;
|
||||
OHIF.viewer.defaultTool = 'wwwc';
|
||||
OHIF.viewer.refLinesEnabled = true;
|
||||
OHIF.viewer.isPlaying = {};
|
||||
|
||||
Meteor.startup(function() {
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer("CornerstoneNewImage", cornerstoneTools.updateImageSynchronizer);
|
||||
OHIF.viewer.functionList = {
|
||||
invert: function(element) {
|
||||
var viewport = cornerstone.getViewport(element);
|
||||
viewport.invert = !viewport.invert;
|
||||
cornerstone.setViewport(element, viewport);
|
||||
},
|
||||
playClip: function(element) {
|
||||
var viewportIndex = $('.imageViewerViewport').index(element);
|
||||
var isPlaying = OHIF.viewer.isPlaying[viewportIndex] || false;
|
||||
if (isPlaying === true) {
|
||||
cornerstoneTools.stopClip(element);
|
||||
} else {
|
||||
cornerstoneTools.playClip(element);
|
||||
}
|
||||
OHIF.viewer.isPlaying[viewportIndex] = !OHIF.viewer.isPlaying[viewportIndex];
|
||||
Session.set('UpdateCINE', Random.id());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (isTouchDevice()) {
|
||||
OHIF.viewer.tooltipConfig = {
|
||||
trigger: 'manual'
|
||||
};
|
||||
} else {
|
||||
OHIF.viewer.tooltipConfig = {
|
||||
trigger: 'hover'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function resizeViewports() {
|
||||
// Handle resizing of image viewer viewports
|
||||
// For some reason, this seems to need to be on
|
||||
// another delay, or the resizing won't work properly
|
||||
viewportResizeTimer = setTimeout(function() {
|
||||
var elements = $('.imageViewerViewport');
|
||||
elements.each(function(index) {
|
||||
var element = this;
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
cornerstone.resize(element, true);
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
|
||||
Session.setDefault('ActiveViewport', 0);
|
||||
Session.setDefault('viewportRows', 1);
|
||||
Session.setDefault('viewportColumns', 1);
|
||||
|
||||
// Avoid doing DOM manipulation during the resize handler
|
||||
// because it is fired very often.
|
||||
// Resizing is therefore performed 100 ms after the resize event stops.
|
||||
var resizeTimer;
|
||||
$(window).on('resize', function() {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(function() {
|
||||
resizeViewports();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
Template.viewer.onRendered(function() {
|
||||
var imageViewer = $("#viewer");
|
||||
if (imageViewer) {
|
||||
$('.navbar-default').css({
|
||||
'background-color': '#000000',
|
||||
'border-color': '#101010'
|
||||
});
|
||||
document.body.style.overflow = "hidden";
|
||||
document.body.style.height = '100%';
|
||||
document.body.style.width = '100%';
|
||||
document.body.style.minWidth = 0;
|
||||
document.body.style.position = 'fixed'; // Prevent overscroll on mobile devices
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
.viewerMain {
|
||||
width: 88%;
|
||||
height: 100%;
|
||||
margin-left: 12%;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<template name="viewerMain">
|
||||
<div class="viewerMain">
|
||||
{{> toolbar}}
|
||||
{{> imageViewerViewports}}
|
||||
<!--TODO: Bottom lesion table container will be here-->
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,12 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Lesion Tracker</title>
|
||||
<meta name="description" content="Prototype viewer application for oncology">
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, minimal-ui, maximum-scale=1, minimum-scale=1" />
|
||||
<link rel="shortcut icon" type="image/png" href="images/logo.png" sizes="16x16 32x32 64x64">
|
||||
<!--Best display for mobile devices-->
|
||||
<meta http-equiv="cleartype" content="on">
|
||||
<meta name="MobileOptimized" content="320">
|
||||
<meta name="HandheldFriendly" content="True">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
</head>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,34 @@
|
||||
Router.configure({
|
||||
layoutTemplate: 'layout',
|
||||
//loadingTemplate: '',
|
||||
notFoundTemplate: 'notFound'
|
||||
});
|
||||
|
||||
|
||||
|
||||
Router.route('/', function () {
|
||||
this.render('worklist', {
|
||||
});
|
||||
});
|
||||
|
||||
ViewerStudies = new Mongo.Collection(null);
|
||||
|
||||
Router.route('/viewer/:_id', {
|
||||
layoutTemplate: 'layout',
|
||||
name: 'viewer',
|
||||
onBeforeAction: function() {
|
||||
var self = this;
|
||||
//Session.set('openNewTabEvent', self);
|
||||
|
||||
Meteor.call('GetStudyMetadata', this.params._id, function(error, study) {
|
||||
//console.log(study);
|
||||
sortStudy(study);
|
||||
|
||||
var studies = [study];
|
||||
Session.set('studies', studies);
|
||||
//Session.set(activeTabId, studies);
|
||||
//Session.set('showContentInTab', true);
|
||||
self.render('viewer');
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
Router.onBeforeAction(function () {
|
||||
|
||||
// User is logged in, go ahead and route them
|
||||
this.next();
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
/*****************************/
|
||||
/* Toggle */
|
||||
/*****************************/
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.dockingContainer, .collapseVertical, .collapseHorizontal {
|
||||
-moz-transition: all 0.3s ease-out;
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
.dockingContainer {
|
||||
-moz-transition: all 0.3s ease-out;
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
.collapseVertical {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.collapseHorizontal {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.btnCollapse{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
background: #f6f6f6;
|
||||
color: #666;
|
||||
font-size: 0.875rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.btnCollapseIcon-collapse{
|
||||
-moz-transform: rotate(180deg);
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
Reference in new issue
Block a user