@galaxyproject/nora
Version:
NORA Medical Imaging Viewer
1,454 lines (1,174 loc) • 280 kB
JavaScript
/**
* @module MiscFunctions
*/
var resources = {
lang: "en",
tooltips: {
en: {
roitool_open: "open roitool",
masterviewport: "use gridding of content as interpolation master",
changeslicing: "change slicing",
centerview: "center view at current location",
resetclims: "reset colormap limits",
changecolormap: "select a different colormap",
switchto3d: "Switch to 3D mode",
zoomviewport: "Zoom viewport",
closeviewport: "close viewport",
dragdropviewport: "drag and drop content",
closetool: "close the tool",
resizetoolvertically: "resize the tool vertically",
dragdroptool: "drag and drop the tool",
patienttrash: "delete selected items or drop an elemet to delete",
refreshtable: "refresh the patient table",
anonymmode: "(un)switch table anonymization",
levelswitcher: "switch table mode",
singlesel: "switch to single patient mode",
tabletoggler: "resize/toggle table",
closeOVL: "close overlay view",
closefiberview: "close fiber viewer",
createvisitmap: "create a visitmap of current selection",
showallfibers: "show all fibers",
fiberpick: "control fiber picker (use annotations to select fibers)",
fibercut: "cut fibers to imaging planes",
cropfibers: "create fiber subset by cropping current selection",
currentpicker: "enable fiberset for picking",
batchtestmode: "send jobs to your matlab console",
isosurfROI: "enable 3D isosurface view of ROI",
jumptoROI: "jump to center of ROI",
selectcolor: "select a different color",
saveuploadROI: "upload/save ROI",
closeROI: "close view of ROI",
createroi: "create ROI",
createemptyroi: "create empty ROI",
makecurrent: "enable ROI for drawing",
playstoptimeseries: "play or stop timeseries movie",
showhide: "show/hide content",
drawonlyonsimilarcolors: "draw on colors similar to center voxel (use colormap limits to control sensitivity)",
regionfillsimilarcolors: "unrestricted region filling (use colormap limits and mouse left/right to control sensitivity)",
regionfillwithinpen: "region filling within pen",
misctools: "miscellaneous tools",
mcpsys: "create mcp reorientation system from two/three markers",
addnewanno: "add new marker to annotation",
closeanno: "remove this annotation",
showhideanno: "show/hide annotation",
jumptopoint: "jump to this point",
delannopoint: "delete this point",
}
}
};
if (typeof jQuery != "undefined")
{
$.prototype.appendTooltip = function(id)
{
var tout;
var fadeOuttimer = {
clear: function() {
clearInterval(this.id)
},
callback: function()
{
inhibit();
}
};
this.on('mouseenter', function(event) {
fadeOuttimer.id = setInterval(function() {
fadeOuttimer.callback()
}, 8000);
clearInterval(tout)
tout = setTimeout(function() {
$("#KJobinfoTooltip").remove();
var ttips = resources.tooltips[resources.lang];
var text = ttips[id];
if (text == undefined)
text = id;
var $div = $("<div id='standardTooltip'> " + text + " </div>");
$div.css("top", event.clientY);
$div.css("left", event.clientX + 15);
$div.appendTo($(document.body));
if ($div.position().left + $div.width() > $(document.body).width())
{
$div.css('left', $(document.body).width() - $div.width() - 10);
$div.css('top', $div.position().top + 15);
}
if ($div.position().top + $div.height() > $(document.body).height())
$div.css('top', $(document.body).height() - $div.height() - 10);
$div.hide();
$div.fadeIn(200);
}, 800);
});
var inhibit = function()
{
fadeOuttimer.clear();
clearInterval(tout);
$("#standardTooltip").remove();
}
this.on('mouseleave mouseclick mousedown', inhibit);
return this;
}
}
function zeroPad(num, places) {
var zero = places - num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}
if (typeof alertify != "undefined")
alertify.lazy_error = function(errstr,type,delay)
{
if (delay == undefined)
delay = 5000;
if (!alertify[type])
{
alertify.error(errstr);
alertify[type] = true;
setTimeout(function() { alertify[type] = false;},delay);
}
}
Array.prototype.chunk =
Object.defineProperty(Array.prototype, 'chunk', {
value:
function(fn, chunksize, delay, aggregate, onready)
{
var forchunk = function(_this, fn, chunksize, delay)
{
if (delay == undefined)
delay = 0;
_this.interval_id = setInterval(function(_this) {
return function()
{
if (_this.cnt == undefined)
_this.cnt = 0;
for (var k = 0; k < chunksize & k + _this.cnt < _this.length; k++)
{
fn(_this[k + _this.cnt], k + _this.cnt, _this);
}
if (aggregate)
{
aggregate(_this.cnt);
}
_this.cnt += chunksize;
if (_this.cnt >= _this.length)
{
clearInterval(_this.interval_id);
delete _this.cnt;
delete _this.interval_id;
if (onready != undefined)
onready();
}
}
}(_this), delay);
}
;
forchunk(this, fn, chunksize, delay);
}
});
//Float32Array.prototype.chunk =
Object.defineProperty(Float32Array.prototype, 'chunk', {
value:
function(fn, chunksize, delay, aggregate, onready)
{
var forchunk = function(_this, fn, chunksize, delay)
{
if (delay == undefined)
delay = 0;
_this.interval_id = setInterval(function(_this) {
return function()
{
if (_this.cnt == undefined)
_this.cnt = 0;
for (var k = 0; k < chunksize & k + _this.cnt < _this.length; k++)
{
fn(_this[k + _this.cnt], k + _this.cnt, _this);
}
if (aggregate)
{
aggregate(_this.cnt);
}
_this.cnt += chunksize;
if (_this.cnt >= _this.length)
{
clearInterval(_this.interval_id);
delete _this.cnt;
delete _this.interval_id;
if (onready != undefined)
onready();
}
}
}(_this), delay);
}
;
forchunk(this, fn, chunksize, delay);
}
}
);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////// Octree
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** The octree used for fast position lookup of fibers
* @class
*/
function Octree(position, size, accuracy) {
this.maxDistance = Math.max(size[0], Math.max(size[1], size[2]));
this.accuracy = 0;
this.root = new Octree.Cell(this,position,size,0);
this.numPoints = 0;
}
Octree.fromBoundingBox = function(bbox) {
return new Octree(bbox.min.clone(),bbox.getSize().clone());
}
;
Octree.MaxLevel = 4;
Octree.prototype.add = function(p, data) {
this.numPoints++;
this.root.add(p, data);
}
;
Octree.prototype.has = function(p) {
return this.root.has(p);
}
;
Octree.prototype.findNearestPoint = function(p, options) {
options.includeData = options.includeData ? options.includeData : false;
options.bestDist = options.maxDist ? options.maxDist : Infinity;
options.notSelf = options.notSelf ? options.notSelf : false;
var result = this.root.findNearestPoint(p, options);
if (result) {
if (options.includeData)
return result;
else
return result.point;
}
else
return null ;
}
;
Octree.prototype.findNearbyPoints = function(p, r, options) {
options = options || {};
var result = {
points: [],
data: []
};
this.root.findNearbyPoints(p, r, result, options);
return result;
}
;
Octree.prototype.getAllCellsAtLevel = function(cell, level, result) {
if (typeof level == 'undefined') {
level = cell;
cell = this.root;
}
result = result || [];
if (cell.level == level) {
if (cell.points.length > 0) {
result.push(cell);
}
return result;
} else {
cell.children.forEach(function(child) {
this.getAllCellsAtLevel(child, level, result);
}
.bind(this));
return result;
}
}
;
Octree.Cell = function(tree, position, size, level) {
this.tree = tree;
this.position = position;
this.size = size;
this.level = level;
this.points = [];
this.data = [];
this.children = [];
}
;
Octree.Cell.prototype.has = function(p) {
if (!this.contains(p))
return null ;
if (this.children.length > 0) {
for (var i = 0; i < this.children.length; i++) {
var duplicate = this.children[i].has(p);
if (duplicate) {
return duplicate;
}
}
return null ;
} else {
var minDistSqrt = this.tree.accuracy * this.tree.accuracy;
for (var i = 0; i < this.points.length; i++) {
var o = this.points[i];
var distSq = (p[0] - o[0]) * (p[0] - o[0]) + (p[1] - o[1]) * (p[1] - o[1]) + (p[2] - o[2]) * (p[2] - o[2]);
if (distSq <= minDistSqrt) {
return o;
}
}
return null ;
}
}
;
Octree.Cell.prototype.add = function(p, data) {
if (this.children.length > 0) {
this.addToChildren(p, data);
} else {
this.points.push(p);
this.data.push(data);
if (this.points.length > 10 && this.level < Octree.MaxLevel) {
this.split();
}
}
}
;
Octree.Cell.prototype.addToChildren = function(p, data) {
for (var i = 0; i < this.children.length; i++) {
if (this.children[i].contains(p)) {
this.children[i].add(p, data);
break;
}
}
}
;
Octree.Cell.prototype.contains = function(p) {
return p[0] >= this.position[0] - this.tree.accuracy
&& p[1] >= this.position[1] - this.tree.accuracy
&& p[2] >= this.position[2] - this.tree.accuracy
&& p[0] < this.position[0] + this.size[0] + this.tree.accuracy
&& p[1] < this.position[1] + this.size[1] + this.tree.accuracy
&& p[2] < this.position[2] + this.size[2] + this.tree.accuracy;
}
;
Octree.Cell.prototype.split = function() {
var x = this.position[0];
var y = this.position[1];
var z = this.position[2];
var w2 = this.size[0] / 2;
var h2 = this.size[1] / 2;
var d2 = this.size[2] / 2;
var whd = [w2, h2, d2];
this.children.push(new Octree.Cell(this.tree,[x, y, z],whd,this.level + 1));
this.children.push(new Octree.Cell(this.tree,[x + w2, y, z],whd,this.level + 1));
this.children.push(new Octree.Cell(this.tree,[x, y, z + d2],whd,this.level + 1));
this.children.push(new Octree.Cell(this.tree,[x + w2, y, z + d2],whd,this.level + 1));
this.children.push(new Octree.Cell(this.tree,[x, y + h2, z],whd,this.level + 1));
this.children.push(new Octree.Cell(this.tree,[x + w2, y + h2, z],whd,this.level + 1));
this.children.push(new Octree.Cell(this.tree,[x, y + h2, z + d2],whd,this.level + 1));
this.children.push(new Octree.Cell(this.tree,[x + w2, y + h2, z + d2],whd,this.level + 1));
for (var i = 0; i < this.points.length; i++) {
this.addToChildren(this.points[i], this.data[i]);
}
this.points = [];
this.data = [];
}
;
Octree.Cell.prototype.squareDistanceToCenter = function(p) {
var dx = p[0] - (this.position[0] + this.size[0] / 2);
var dy = p[1] - (this.position[1] + this.size[1] / 2);
var dz = p[2] - (this.position[2] + this.size[2] / 2);
return dx * dx + dy * dy + dz * dz;
}
Octree.Cell.prototype.findNearestPoint = function(p, options) {
var nearest = null ;
var nearestData = null ;
var bestDist = options.bestDist;
if (this.points.length > 0 && this.children.length == 0) {
for (var i = 0; i < this.points.length; i++) {
var dist = this.points[i].distance(p);
if (dist <= bestDist) {
if (dist == 0 && options.notSelf)
continue;
bestDist = dist;
nearest = this.points[i];
nearestData = this.data[i];
}
}
}
var children = this.children;
var children = this.children
.map(function(child) {
return {
child: child,
dist: child.squareDistanceToCenter(p)
}
})
.sort(function(a, b) {
return a.dist - b.dist;
})
.map(function(c) {
return c.child;
});
if (children.length > 0) {
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.points.length > 0) {
if (p[0] < child.position[0] - bestDist || p[0] > child.position[0] + child.size[0] + bestDist ||
p[1] < child.position[1] - bestDist || p[1] > child.position[1] + child.size[1] + bestDist ||
p[2] < child.position[2] - bestDist || p[2] > child.position[2] + child.size[2] + bestDist
) {
continue;
}
var childNearest = child.findNearestPoint(p, options);
if (!childNearest || !childNearest.point) {
continue;
}
var childNearestDist = childNearest.point.distance(p);
if (childNearestDist < bestDist) {
nearest = childNearest.point;
bestDist = childNearestDist;
nearestData = childNearest.data;
}
}
}
}
return {
point: nearest,
data: nearestData
}
}
;
Octree.Cell.prototype.findNearbyPoints = function(p, r, result, options) {
for (var i = 0; i < this.points.length; i++) {
var dx = this.points[i][0] - p[0];
var dy = this.points[i][1] - p[1];
var dz = this.points[i][2] - p[2];
var dist = (dx * dx + dy * dy + dz * dz);
if (dist <= r * r) {
if (dist == 0 && options.notSelf)
continue;
result.points.push(this.points[i]);
if (options.includeData)
result.data.push(this.data[i]);
}
}
var children = this.children
if (children.length > 0) {
for (var i = 0; i < children.length; i++) {
var child = children[i];
//if (child.points.length > 0)
{
if (p[0] < child.position[0] - r || p[0] > child.position[0] + child.size[0] + r ||
p[1] < child.position[1] - r || p[1] > child.position[1] + child.size[1] + r ||
p[2] < child.position[2] - r || p[2] > child.position[2] + child.size[2] + r
) {
continue;
}
child.findNearbyPoints(p, r, result, options);
}
}
}
}
;
function executeImageWorker(execObj,Buffers,progress,onready,worker)
{
if (worker == undefined)
{
var scriptname = 'KImageProcWorker.js' + '?' + static_info.softwareversion;
if (typeof url_pref != "undefined")
scriptname = url_pref + scriptname;
worker = new Worker(scriptname);
worker.postMessage = worker.webkitPostMessage || worker.postMessage;
worker.addEventListener('message', function(e) {
e = e.data;
if (e.msg == 'done')
{
if (progress != undefined)
progress();
onready(e);
}
else
if (progress != undefined)
progress(e.msg);
}, false);
worker.kill = function()
{
worker.postMessage({'msg':'kill'},[]);
}
}
worker.postMessage(execObj,Buffers); // Send data to our worker.
return worker;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////// generic context menu
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** A generic contextmenu
* @param {function} themenu - A function returning an "ul" containing the menu
* @param {function} theselfun - called on menu selection with signature theselfun(onchoice,mouseupevent,mousedownevent). First argument contains onchoice attribute of menu "li"
* @param {logical} loose - ??
* @param {logical} keepOpenAfterClick - menu disappears only on mouse leave
* @param {logical} selectonrelease - allow item selection on moushold- mouseup, can be dangerous for unexperienced users
* @return {function} - a menu creater function that should be called upon click/mousedown etc.
*/
function KContextMenu(themenu, theselfun, loose, keepOpenAfterClick, eventonmenu, selectonmouseup)
{
var last_ev;
var createFun = function(ev)
{
if (ev != undefined)
{
ev.preventDefault();
ev.stopPropagation();
}
last_ev = ev;
var target = ev.target;
var $cmdiv = $("<div class='patientTableContextmenu'>");
var mymenu = themenu(ev);
if (mymenu == undefined)
return;
// this was always called twice, with (ev)...?
//var $menu = themenu(ev).appendTo($cmdiv);
var $menu = mymenu.appendTo($cmdiv);
// correct for chrome bug, where a hover is not triggered during mousedown
$menu.find("li").each(function(i, a) {
$(a).mouseenter(function() {
$(this).addClass('jsHover');
})
.mouseleave(function() {
$(this).removeClass('jsHover');
})
});
if(keepOpenAfterClick)
{
var offs_top = -10;
var offs_left = -5;
}
else
{
var offs_top = 5;
var offs_left = 5;
}
$cmdiv.css("display", "block");
$cmdiv.css({
left: ev.pageX + offs_left,
top: ev.pageY + offs_top
});
$cmdiv.show();
var selFun = function(ev2)
{
var str;
var $target = $(ev2.target)
for (var k = 0; k < 3; k++)
{
str = $target.attr("onchoice")
if (str != undefined)
break;
else
$target = $target.parent();
}
if (str != 'preventSelection')
{
ev2.preventDefault();
ev2.stopPropagation();
if (str != undefined | !loose) // (keepOpenAfterClick | !loose ) // | ev2.type == "mousedown" | ev2.type == "mouseup") )
{
$cmdiv.remove();
fadeOuttimer.clear();
$(document.body).off("mouseup mousedown");
}
if (theselfun(str, ev2, ev) == "close")
return;
if (keepOpenAfterClick)
createFun(last_ev);
}
}
;
$(document.body).append($cmdiv);
var uls = $cmdiv.find("ul,div");
var left = 0;
for (var k = 0; k < uls.length;k++)
{
var $ul = $(uls[k]);
var disp = $ul.css('display');
if ($ul.offset().left +left + $ul.width() > $(document.body).width())
$ul.css('left',-($ul.offset().left +left + $ul.width() - $(document.body).width())- offs_left-20);
if ($(document.body).height() != 0 && $ul.offset().top + $ul.height() > $(document.body).height())
$ul.css('top', -($ul.offset().top + $ul.height() - $(document.body).height())- offs_top-10);
if (k==0)
left = $ul.offset().left + $ul.width()-20 ;
}
var $which = $(document.body);
if (eventonmenu)
{
$which = $cmdiv;
$(document.body).on("mousedown",function()
{
$(document.body).off("mousedown");
$cmdiv.off("mouseup mousedown");
$cmdiv.remove();
})
}
if (keepOpenAfterClick || selectonmouseup === false )
$which.on("mousedown", selFun);
else
$which.on("mouseup mousedown", selFun);
$which.on("contextmenu",function(e)
{
e.preventDefault();
});
$cmdiv.on("mouseleave", function(ev) {
$which.off("mouseup mousedown");
fadeOuttimer.clear();
$cmdiv.remove();
});
var fadeOuttimer = {
clear: function() {
clearInterval(this.id)
},
callback: function()
{
this.clear();
$which.off("mouseup mousedown");
$cmdiv.fadeOut(1000);
}
};
fadeOuttimer.id = setInterval(function() {
fadeOuttimer.callback()
}, 10000000);
}
return createFun;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////// shared links
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** open a shared link. Information comes from php within "sharedLink" variable
* @param {function} onready - called after establishment of shared viewing state
*/
function openSharedLink(sharedLink,onready)
{
// extend the state with the shared link. Can be done now safely, as the presets are not overwritten
// dangerous. can destroy project state and everything ...
//$.extend(state, share dLink, true);
// etabslish tree state
if (userinfo.username != guestuser && sharedLink.project != undefined)
{
selectProject(sharedLink.project, function() {
// set settings
if (sharedLink.ViewerSettings !== undefined)
{
state.viewer = sharedLink.ViewerSettings;
stateManager.applyState(state);
}
switchto(state.viewer.selectionMode,undefined,function()
{
patientTableMirror.nodesExpanded = sharedLink.expandedNodes || [];
patientTableMirror.selectedItems = sharedLink.selectedItems || [];
patientTableMirror.mirrorState();
currentPSID = sharedLink.currentPSID || {};
if (currentPSID.patients_id)
{
if (state.viewer.selectionMode[1] == 's')
{
setEditModeText(currentPSID.patients_id + riddelim + currentPSID.studies_id);
}
if (state.viewer.selectionMode[1] == 'p')
{
setEditModeText(currentPSID.patients_id);
}
}
loadSharedContent();
});
});
}
else
{
// set settings
if (sharedLink.ViewerSettings !== undefined)
{
state.viewer = sharedLink.ViewerSettings;
stateManager.applyState(state);
}
loadSharedContent();
}
function loadSharedContent()
{
$(document.body).addClass("wait");
if (sharedLink.toolstate)
KToolWindow.reestablishToolState(sharedLink.toolstate);
if (sharedLink.naviMode != undefined)
{
KViewer.navigationTool.switchToNavimode( sharedLink.naviMode);
if (sharedLink.navi_reorientationMatrix!= undefined && sharedLink.navi_reorientationMatrix.notID)
{
KViewer.reorientationMatrix.notID = true;
var transform = sharedLink.navi_reorientationMatrix;
KViewer.reorientationMatrix.name = transform.name;
KViewer.reorientationMatrix.matrix = math.matrix(transform.matrix);
KViewer.navigationTool.transform.update();
}
//KViewer.reorientationMatrix = sharedLink.navi_reorientationMatrix;
}
// load annos
if (sharedLink.annotations != undefined)
{
if (markerProxy != undefined)
{
markerProxy.delAll();
markerProxy.import(sharedLink.annotations.content);
if (sharedLink.annotations.panelenabled)
{
for(var p in markerProxy.markersets)
markerProxy.markersets[p].showPanel();
}
}
}
// load atlas deffield
if (sharedLink.atlas_defField != undefined)
KViewer.dataManager.loadData({
URLType: 'serverfile',
fileID: sharedLink.atlas_defField,
json: {
project: sharedLink.project
},
callback: KViewer.atlasTool.addAtlas
});
// load viewport content
var params = sharedLink.viewports || [];
var q = [];
var derived_q = [];
if (sharedLink.atlases != undefined & !electron)
for (var k = 0; k < sharedLink.atlases.length; k++)
{
var param = ({ URLType: 'serverfile', fileID:sharedLink.atlases[k].fileID,json:{project:sharedLink.atlases[k].project},intent:{atlas:true,project:sharedLink.atlases[k].project}});
if (param.json.project == undefined)
param.json.project = sharedLink.project
q.push(param);
}
for (var k = 0; k < params.length; k++)
{
if (params[k])
{
if (params[k].fileID.refvisit_tck)
{
derived_q.push(params[k])
continue;
}
else if (params[k].id.search("atlas") > -1)
{
if (params[k].project != undefined)
params[k].json = {
project: params[k].project
};
else
params[k].json = {
project: sharedLink.project
//static_info.atlas.project
};
params[k].fileID = params[k].fileID.replace("atlas_", "");
}
else
params[k].json = {
project: sharedLink.project
}
q.push(params[k]);
}
}
if (electron)
{
for (var k = 0; k < q.length;k++)
{
var filepath = q[k].fileID;
if (sharedLink.absolutePath)
filepath = path.join(sharedLink.absolutePath,filepath);
filepath = filepath.replace(/\\/g,"/"); // for windows
q[k].URLType = "localfile";
q[k].file = {name:filepath,local:true};
q[k].filename = filepath;
q[k].fileID = "localfile:"+filepath;
}
}
setTimeout(function(){
$(document.body).addClass("wait");
loadingQueue.execQueue(q, function() {
if (sharedLink.navi_movingObjs && sharedLink.navi_movingObjs.length > 0)
{
for (var k = 0; k < sharedLink.navi_movingObjs.length; k++)
KViewer.navigationTool.movingObjs[sharedLink.navi_movingObjs[k]] =
KViewer.dataManager.getFile(sharedLink.navi_movingObjs[k]);
KViewer.navigationTool.updateMoving();
}
if (sharedLink.mainviewport != undefined)
KViewer.toggleMainViewport(sharedLink.mainviewport, true);
// KViewer.resetCrossHair();
if (sharedLink.position)
KViewer.currentPoint = math.matrix(sharedLink.position);
if (sharedLink.ironSight)
{
ironSight.toggle();
}
if (sharedLink.WMQLpanels != undefined)
{
for (var k = 0; k < sharedLink.WMQLpanels.length;k++)
{
KWMQLPanel.openPanel(KViewer.obj3dTool.objs[sharedLink.WMQLpanels[k].tract_id],
KViewer.atlasTool.objs[sharedLink.WMQLpanels[k].atlas_id],
sharedLink.WMQLpanels[k]);
}
}
signalhandler.send("reslice positionChange");
for (var k=0;k < derived_q.length;k++)
{
if (derived_q[k].fileID.refvisit_tck != undefined)
{
var vport_id = derived_q[k].fileID.viewport_id;
var vmap_params = derived_q[k].fileID.refvisit_params;
var fibid = derived_q[k].fileID.refvisit_tck;
var objs = KViewer.viewports[vport_id].medViewer.objects3D;
for (var j = 0; j < objs.length;j++)
if (KViewer.viewports[vport_id].medViewer.objects3D[j].fibers &&
KViewer.viewports[vport_id].medViewer.objects3D[j].fibers.fileID == fibid)
{
var tck = KViewer.viewports[vport_id].medViewer.objects3D[j];
var fobj;
if (vmap_params.terminal)
{
tck.visitworker_terms = tck.createVisitMap(vmap_params.undersamp,vmap_params.terminal,true,true);
fobj = tck.visitworker_terms.fobj;
}
else
{
tck.visitworker = tck.createVisitMap(vmap_params.undersamp,undefined,true,true);
fobj = tck.visitworker.fobj;
}
var target_vid = derived_q[k].intent.viewportID
KViewer.viewports[target_vid].setContent(fobj,{intent:derived_q[k].intent});
fobj;
}
}
}
/*
setTimeout(function()
{
for (var r = 0;r < markerProxy.markersets.length;r++)
{
for (var x in markerProxy.markersets[r].onupdate)
markerProxy.markersets[r].onupdate[x]();
}
},1000);
*/
if (sharedLink.TableHidden)
KViewer.toggleTableHide();
if (markerProxy != undefined && sharedLink.currentAnnot != undefined)
markerProxy.setCurrentSet(sharedLink.currentAnnot,true);
if (sharedLink.zoomedViewport != -1 && KViewer.viewports[sharedLink.zoomedViewport] != undefined )
KViewer.viewports[sharedLink.zoomedViewport].zoomViewPort();
$(document.body).removeClass("wait");
$("#KLoadingFrame").css('display','none')
if (onready)
onready();
});
},0);
}
}
function saveWorkstate(that)
{
var s = gatherState('savestate');
if (electron)
{
uploadJSON("workstate.json",s,{subfolder:'workstates',tag:'workstate'},function(){});
}
else
alertify.prompt("Enter a name for of state", function(e,name)
{
if (e)
{
that.lastProjectStatename = name;
uploadJSON(name,s,{subfolder:'workstates',tag:'workstate'},function(){});
}
} ,that.lastProjectStatename);
}
/** objectifies viewing state including all currently loaded files etc.
* @return {object} - an object containg all state information
*/
function gatherState(issuer)
{
function mapID(obj)
{
var id ;
if (obj.content && obj.content.refvisit_params)
{
id = {refvisit_tck:obj.content.refvisit_tck.fibers.fileID,
viewport_id:obj.content.refvisit_tck.viewer.viewport.viewPortID,
refvisit_params:obj.content.refvisit_params}
return id;
}
if (obj.fileID)
id = obj.fileID;
if (obj.currentFileID)
id = obj.currentFileID;
if (obj.trackingVolID)
id = obj.trackingVolID;
if (id == undefined)
return undefined;
if (electron)
{
var file = KViewer.dataManager.getFile(id);
return file.fileinfo.SubFolder + "/" + file.fileinfo.filename;
}
else
{
return id;
}
}
// gather viewport content and overlays
var imgs = [];
for (var k = 0; k < KViewer.viewports.length; k++)
{
if (KViewer.viewports[k] == undefined)
continue;
if(KViewer.viewports[k].getCurrentViewer)
var viewer = KViewer.viewports[k].getCurrentViewer();
else
viewer = undefined;
if (viewer != undefined
&& ( ( viewer.currentFileID != undefined & viewer.currentFileID != "") || (viewer.nii != undefined && viewer.nii.dummy != undefined) ) )
{
var myid = "ID" + viewer.currentFileID;
if (viewer.viewerType == "medViewer")
{
/* that.zoomFac = zl[0];
that.zoomOriginY = zl[1];// / hei_cm * $canvas.height();
that.zoomOriginX =
*/
var gl_props;
if (viewer.isGLenabled())
gl_props = {alpha:viewer.gl.camera.alpha,
beta:viewer.gl.camera.beta,
radius:viewer.gl.camera.radius,
planesVisibility:viewer.gl.getPlanesVisibility()};
if (viewer.currentFileID != undefined)
{
var main_img = {
id: myid,
fileID: mapID(viewer), //viewer.currentFileID,
URLType: 'serverfile',
name:viewer.currentFilename,
intent:
{
viewportID: k,
zooms: viewer.getRelativeZoomLims(),
cmap: viewer.histoManager.cmapindex,
clim: viewer.histoManager.getManuallyEnteredClim(issuer == 'savestate'),
gl: viewer.isGLenabled(),
gl_props:gl_props,
isosurf: (viewer.refSurfView!=undefined)?viewer.refSurfView.getViewProperties():undefined,
slicing: viewer.getSlicingDimOfWorld(),
showcolored_type:viewer.showcolored_type,
showcolored:viewer.showcolored,
transfactor:viewer.transfactor
}
};
if (viewer.mosaicview && viewer.mosaicview.active)
{
main_img.mosaic = {border:viewer.mosaicview.border,
nx: viewer.mosaicview.nx,
nx_cont: viewer.mosaicview.nx_cont,
zoom: viewer.mosaicview.zoom,
start:viewer.mosaicview.start,
end:viewer.mosaicview.end};
}
if (viewer.nii && viewer.nii.quiver_params)
{
main_img.intent.quiver_params = viewer.nii.quiver_params;
}
imgs.push(main_img);
}
if (viewer.overlays != undefined)
for (var j = 0; j < viewer.overlays.length; j++)
{
var myid = "ID" + viewer.overlays[j].currentFileID;
imgs.push({
id: myid + "ovl",
fileID: mapID(viewer.overlays[j]),
name:viewer.overlays[j].currentFilename,
URLType: 'serverfile',
intent:
{
overlay: true,
viewportID: k,
isosurf: (viewer.overlays[j].refSurfView!=undefined)?viewer.overlays[j].refSurfView.getViewProperties():undefined,
cmap: viewer.overlays[j].histoManager.cmapindex,
transparent: viewer.overlays[j].histoManager.blending,
clim: viewer.overlays[j].histoManager.getManuallyEnteredClim(issuer=='savestate'),
showcolored:viewer.overlays[j].showcolored,
showcolored_type:viewer.overlays[j].showcolored_type,
posnegsym:viewer.overlays[j].histoManager.posnegsym,
blocky:viewer.overlays[j].histoManager.blocky,
visible:viewer.overlays[j].visible,
hideview:viewer.overlays[j].hideview,
quiver_params:viewer.overlays[j].nii.quiver_params,
outlines: (viewer.overlays[j].outlines != undefined)?((viewer.overlays[j].color != undefined)?viewer.overlays[j].color:0):undefined
}
});
}
if (viewer.ROIs != undefined)
for (var j = 0; j < viewer.ROIs.length; j++)
{
var myid = "ID" + viewer.ROIs[j].roi.fileID;
var roi = viewer.ROIs[j].roi;
var isosurf;
// if (viewer.ROIs[j].refSurfView != undefined)
// isosurf = true;
imgs.push({
id: myid + "roi",
fileID: mapID(roi),
name:roi.filename,
URLType: 'serverfile',
intent:
{
roi: true,
isosurf: (viewer.ROIs[j].refSurfView!=undefined)?viewer.ROIs[j].refSurfView.getViewProperties():undefined,
color: viewer.ROIs[j].color,
viewportID: k,
visible:viewer.ROIs[j].visible
}
});
}
if (viewer.objects3D != undefined)
for (var j = 0; j < viewer.objects3D.length; j++)
{
var obj = viewer.objects3D[j];
var fid, assoc_annot;
var clim;
var more_intent;
if (obj.getViewProperties)
more_intent = obj.getViewProperties()
else
more_intent = {};
if (viewer.currentFileID == undefined)
more_intent.gl_props = gl_props
if (obj.fibers != undefined | obj.contour != undefined)
{
if (obj.fibers)
{
fid = mapID(obj.fibers);
if (obj.fibers.tckjsonref)
fid = mapID(obj.fibers.tckjsonref);
else
{
if (obj.children && obj.children.length > 0)
{
var json = KViewer.obj3dTool.save(obj.fibers,undefined,true)
more_intent.jsonsubsets = json;
}
}
if (obj.Selection && obj.parent)
more_intent.select = obj.Selection.name;
else
more_intent.select = 'all';
if ((obj.subsetToDisplay != undefined && obj.subsetToDisplay.length > 0) |
(obj.isParentView && obj.subsetToDisplay == undefined))
{
more_intent.visible = true; // not yet
more_intent.donotmakecurrent = true; // not yet
}
else
{
more_intent.visible = false; // not yet
more_intent.donotmakecurrent = true; // not yet
}
if (obj.isCurrent)
more_intent.donotmakecurrent = false;
if (obj.trackingVol)
{
fid = mapID(obj);
more_intent.createFiberTracking = obj.getViewProperties();
}
var annots = markerProxy.getSets();
for (var r = 0;r < annots.length;r++)
if (annots[r].uuid == obj.associated_annotation)
{
more_intent.assoc = r;
break;
}
}
else
{
fid = mapID(obj.contour);
more_intent.select = obj.select;
}
more_intent.fibcut = obj.fibcut;
more_intent.fibcut_proj = obj.fibcut_proj;
more_intent.fibcut_thres = obj.fibcut_thres;
more_intent.color = obj.color;
}
var atlasiso = undefined
var project = undefined;
if (obj.surf != undefined)
{
fid = mapID(obj.surf);
for (var jj=0;jj <obj.overlays.length; jj++)
{
var ovl = obj.overlays[jj];
imgs.push({
id: myid + "roi",
fileID: mapID(ovl),
URLType: 'serverfile',
name:ovl.filename,
intent:
{
surfcol: fid,
cmap: ovl.histoManager.cmapindex,
clim:ovl.histoManager.clim,
viewportID: k,
}})
}
if (obj.surf.atlasref)
{
fid = mapID(obj.surf.atlasref.atlas),
project = obj.surf.atlasref.atlas.project,
atlasiso = obj.surf.atlasref.label;
}
else if (obj.refRoiView != undefined)
continue;
}
if (obj.cmat != undefined)
{
fid = mapID(obj.cmat);
clim = obj.histoManager.getManuallyEnteredClim(issuer == 'savestate');
}
imgs.push({
id: fid + (atlasiso?"atlas":"") + "3D",
fileID: fid,
project: project,
name:obj.filename,
URLType: 'serverfile',
intent: $.extend(
{
GL: true,
gl: true,
atlasiso:atlasiso,
viewportID: k,
cuts: obj.cuts,
assoc_annot: assoc_annot,
clim: clim
},more_intent)
});
if (obj.surf != undefined)
{
}
}
if (viewer.atlas != undefined)
for (var j = 0; j < viewer.atlas.length; j++)
{
var obj = viewer.atlas[j];
imgs.push({
id: myid + "atlas",
fileID: mapID(obj.atlas),
project: obj.atlas.project,
URLType: 'serverfile',
intent:
{
viewportID: k,
hasPanel : ( obj.atlas.panel != undefined)? obj.atlas.panel.getState() : undefined,
}
});
}
}
else if (viewer.viewerType == "formViewer")
{
if (viewer.currentFileID == 'NA')
{
var fid = KViewer.formManager.getFormByID(viewer.currentFormID).name;
imgs.push({
id: "ID" +