UNPKG

@galaxyproject/nora

Version:

NORA Medical Imaging Viewer

1,454 lines (1,174 loc) 280 kB
/** * @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" +