UNPKG

@galaxyproject/nora

Version:

NORA Medical Imaging Viewer

1,314 lines (1,077 loc) 521 kB
// ====================================================================================== // ====================================================================================== // ============= KMedViewer // ====================================================================================== // ====================================================================================== function KMedViewer(viewport, master) { /** @class * @alias KMedViewer */ var that = KPrototypeViewer(viewport, master); that.viewerType = 'medViewer'; that.type = 'mainview'; var $container = that.$container; var $topRow = that.$topRow; var toolbar = that.toolbar; toolbar.$info.hide(); var $canvascontainer = $("<div class='KViewPort_canvascontainer'></div>").appendTo($container); that.$canvascontainer = $canvascontainer; // attach the histogram that.histoManagercnt = 0; var histoManager = createHistoManager(that); /** @type {KHistoManager} */ that.transfactor = 1; that.histoManager = histoManager; that.visible = true; that.isFlatMap = false; histoManager.blending = undefined; histoManager.posnegsym = undefined; histoManager.blocky = undefined; histoManager.onclimchange = function(ev) { sliceDrawUpdateNeeded = true; histoManager.clim_manually_modified = true; signalhandler.send("climChange", { id: that.currentFileID, val: histoManager.clim, ev: ev }); } var infomenu = function(_that) { return KContextMenu(function() { var nii = that.nii; var msz; if (nii.sizes.length > 3) msz = "matrix: " + nii.sizes[0].toFixed(0) + '&nbsp;&nbsp;' + nii.sizes[1].toFixed(0) + '&nbsp;&nbsp;' + nii.sizes[2].toFixed(0) + '&nbsp;&nbsp;' + nii.sizes[3].toFixed(0); else msz = "matrix: " + nii.sizes[0].toFixed(0) + '&nbsp;&nbsp;' + nii.sizes[1].toFixed(0) + '&nbsp;&nbsp;' + nii.sizes[2].toFixed(0); if (nii.currentTimePoint.t != 0) msz += " (t:" + (nii.currentTimePoint.t + 1) + ")"; if (that.currentFileinfo) var psid = that.currentFileinfo.patients_id + " " + that.currentFileinfo.studies_id; else var psid = "localfile"; msz = that.currentFilename + " <br> ID: " + psid + "<br>" + msz + "<br>voxsize: " + nii.voxSize[0].toFixed(1) + '&nbsp;&nbsp;' + nii.voxSize[1].toFixed(1) + '&nbsp;&nbsp;' + nii.voxSize[2].toFixed(1) return $("<ul class='menu_context'>").append($("<li >" + msz + " </li>")); }, function(str, ev) {}) }(that); that.switchToMosaic = function() { if (gl_enabled) toggle3D(); that.mosaicview.active = true; setCanvasLayout(); drawSlice(); } that.switchToSingle= function() { if (gl_enabled) toggle3D(); if (that.mosaicview.active) that.mosaicview.active = false; setCanvasLayout(); if (!that.mosaicview.active) drawSlice(); } that.switchTo3D = function(callback) { if (that.mosaicview.active) that.mosaicview.active = false; if (!gl_enabled) toggle3D(undefined,callback); else { setCanvasLayout(); drawSlice(); } } that.toggle = function(e) { var vis = !that.visible; if (!e.shiftKey) { master.iterateMedViewers(function(m) { if (that.currentFileID == m.currentFileID) { m.setVisibility(vis) } }); } else that.setVisibility(vis) } that.setVisibility = function(visible) { if (!visible) { that.visible = false; toolbar.$eye.css('color', 'red'); } else { that.visible = true; toolbar.$eye.css('color', ''); } that.drawSlice({ mosaicdraw: true }); } that.viewContextMenu = new KContextMenu( function() { var $menu = $("<ul class='menu_context'>"); var name = ['Sagittal', 'Coronal', 'Transversal']; $menu.append($("<hr width='100%'> ")); $menu.append($("<span> &nbsp View</span>")); $menu.append($("<hr width='100%'> ")); var sel = (!gl_enabled && !that.mosaicview.active) ? 'check-' : ''; $menu.append($("<li onchoice='single' > <i onchoice='single' class='fa fa-" + sel + "circle-o'></i><i class='leftaligned fa fa-user'></i> Single slice </li>")); var sel = that.mosaicview.active ? 'check-' : ''; $menu.append($("<li onchoice='mosaic' > <i onchoice='mosaic' class='fa fa-" + sel + "circle-o'></i> <i class='leftaligned fa fa-th'></i> Mosaic </li>")); var sel = gl_enabled ? 'check-' : ''; if (typeof KMedImg3D != "undefined") $menu.append($("<li onchoice='3dview' > <i onchoice='3dview' class='fa fa-" + sel + "circle-o'></i> <i class='leftaligned fa fa-cube'></i> 3D view </li>")); // $menu.append($("<li onchoice='curveview' > <i onchoice='curveview' class='fa fa-" + sel + "circle-o'></i> <i class='leftaligned fa fa-line-chart'></i> Curve view </li>")); $menu.append($("<hr width='100%'> ")); var sel = worldLockedToMaster ? 'check-' : ''; $menu.append($("<li onchoice='lock' > Global coordinates<i onchoice='lock' class='fa fa-" + sel + "square-o'></i> </li>")); var permstr = "<li onchoice='...' >Permutation<i onchoice='lock' class='fa fa-caret-right'></i> <ul>" ; for (var k = 0; k < presetForm_viewer_permorder.choices.length;k++ ) { var sel = (that.nii.reordering == presetForm_viewer_permorder.ids[k]) ? 'check-' : ''; permstr += " <li onchoice='permorder_"+presetForm_viewer_permorder.ids[k]+"' >"+ presetForm_viewer_permorder.choices[k] + "<i onchoice='lock' class='fa fa-"+sel+"square-o'></i> </li> " } permstr += "</ul></li>"; $menu.append($(permstr)); if (!gl_enabled) { $menu.append($("<hr width='100%'> ")); $menu.append($("<span> &nbsp Slicing</span>")); $menu.append($("<hr width='100%'> ")); var perm = [0, 1, 2]; //[viewer.nii.permutationOrder[0],viewer.nii.permutationOrder[1],viewer.nii.permutationOrder[2]]; perm[-1] = -1; for (var k = 0; k < 3; k++) { var sel = ''; // if (slicingDimOfWorld == that.nii.permutationOrder[k]) // sel = 'check-'; if (slicingDimOfWorld == k) sel = 'check-'; $menu.append($("<li onchoice='vis_" + k + "' > " + name[k] + " <i onchoice='vis_" + k + "' class='fa fa-" + sel + "circle-o'></i> </li>")); } } return $menu; } ,function(str, ev) { if (str != undefined) { if (str.search("vis") != -1) { setSlicingDimOfWorld(parseInt(str.substring(4))); } else if (str == "single") { that.switchToSingle(); } else if (str == "mosaic") { that.switchToMosaic(); } else if (str == "3dview") { that.switchTo3D(); } else if (str == "curveview") { if (that.mosaicview.active) that.mosaicview.active = false; if (gl_enabled) toggle3D(); KMedImgCurve( that ); } else if (str == 'lock') { changeWorldLock(); // if (worldLockedToMaster) // customPoint = math.matrix(getWorldPosition()); // worldLockedToMaster = !worldLockedToMaster; // drawSlice({ // mosaicdraw: true // }); } else if (str.substring(0,10) == 'permorder_') { var id = str.substring(10); that.niiOriginal.applyReordering(id); signalhandler.send("updateImage",{id:that.currentFileID}); } } } ,undefined,false); function KIcon(name,$div,style) { if (style == undefined) style = ""; var $icon; if (name == "planecube") { style = style = style +"stroke:lightgray;stroke-width:1"; $icon = []; $icon[2] = $("<div> <svg style='' height=12 width=12>"+ " <polygon points='1,3 1,9 6,11 6,5' style='fill:none;"+style+"' />"+ " <polygon points='11,3 11,9 6,11 6,5' style='fill:none;"+style+"' />"+ " <polygon points='1,3 6,5 11,3 6,1' style='fill:yellow;"+style+"' />"+ +"</svg> </div>"); $icon[1] = $("<div> <svg style='' height=12 width=12>"+ " <polygon points='1,3 1,9 6,11 6,5' style='fill:none;"+style+"' />"+ " <polygon points='11,3 11,9 6,11 6,5' style='fill:yellow;"+style+"' />"+ " <polygon points='1,3 6,5 11,3 6,1' style='fill:none;"+style+"' />"+ +"</svg> </div>"); $icon[0] = $("<div> <svg style='' height=12 width=12>"+ " <polygon points='1,3 1,9 6,11 6,5' style='fill:yellow;"+style+"' />"+ " <polygon points='11,3 11,9 6,11 6,5' style='fill:none;"+style+"' />"+ " <polygon points='1,3 6,5 11,3 6,1' style='fill:none;"+style+"' />"+ +"</svg> </div>"); } $div.append($icon); return $icon; } toolbar.$cmapReset = $("<div class='KViewPort_tool KViewPort_tool_cmapReset'><i class='fa fa-reply fa-1x'></i></div>").click(function() { resetColorMapLims(); }).appendTooltip("resetclims") toolbar.$cmap = $("<div class='KViewPort_tool KViewPort_tool_cmap'><i class='fa fa-empty fa-1x'>&nbsp&nbsp&nbsp&nbsp</i></div>").click(histoManager.cmapSelectorMenu).appendTooltip("changecolormap") toolbar.$quiver = $("<div class='KViewPort_tool'> <i class='fa fa-code-fork fa-1x'> </div>").click(function(e) { quiver.menu(e,that) }).appendTooltip("quiverprops") that.quiverdiv = toolbar.$quiver toolbar.$info = $("<div class='KViewPort_tool'> <i class='fa fa-info-circle fa-1x'> </div>").click(infomenu); toolbar.$lock = $("<div class='KViewPort_tool'> <i class='fa fa-lock fa-1x'> </div>").click(changeWorldLock); toolbar.$view = $("<div class='KViewPort_tool'> <i class='fa fa-photo fa-1x'> </div>").click(that.viewContextMenu); toolbar.$eye = $("<div class='KViewPort_tool'> <i class='fa fa-eye fa-1x'> </div>").click(that.toggle); toolbar.$createIso = $("<div class='KViewPort_tool'> <i class='fa fa-play fa-1x'> </div>"); toolbar.$toggle3D = $("<div class='KViewPort_tool KViewPort_tool_toggle3D'><i class='fa fa-1x'><span>3D</span></i></div>").click(function() { toggle3D() }).appendTooltip("switchto3d"); toolbar.$slicingDim = $("<div class='KViewPort_tool KViewPort_tool_slicingDim'></div>").click(toggleSlicingDim).appendTooltip("changeslicing") toolbar.$sliceCubes = KIcon('planecube',toolbar.$slicingDim); toolbar.attach(toolbar.$cmapReset).attach(toolbar.$cmap).attach(toolbar.$info).attach(toolbar.$quiver).attach(toolbar.$toggle3D).attach(toolbar.$lock).attach(toolbar.$view).attach(toolbar.$eye).attach(toolbar.$slicingDim); var layoutbar = that.layoutbar; layoutbar.$slicing = $("<div class='KViewPort_tool_layout'><i class='fa fa-1x'></i></div>").click(toggleSlicingDim).appendTooltip("changeslicing") if (typeof KMedImg3D != "undefined") { layoutbar.$shortcut3d = $("<span class='KViewPort_tool_layout layout3dshortcut'> 3D</span>"); layoutbar.$shortcut3d.click(function() { toggle3D(); }); } layoutbar.$sliceCubes = KIcon('planecube',layoutbar.$slicing); layoutbar.$center = $("<div class='KViewPort_tool_layout'><i class='fa fa-dot-circle-o fa-1x'></i></div>").click( function() { signalhandler.send("centralize",{viewer:that}); } ).appendTooltip("centerview"); layoutbar.attach(layoutbar.$slicing); if (typeof KMedImg3D != "undefined") layoutbar.attach(layoutbar.$shortcut3d); // ******** slide slices and slide zoom layoutbar.$slideslices = $("<span class='KViewPort_tool_layout'> <i class='fa fa-unsorted fa-1x'></i> </span>"); layoutbar.$slidezoom = $("<span class='KViewPort_tool_layout'> <i class='fa fa-search fa-1x'></i> </span>"); // slice slider attachMouseSlider(layoutbar.$slideslices, { mousedown: function(){ return { startval: currentSlice, startval_percent: currentSlice / (that.nii.sizes[slicingDimOfArray]-1) } } , mousemove:function(ev,dx,dy,mousedownvar) { return that.setSlicePos(slicingDimOfArray, mousedownvar.startval - that.nii.arrayReadDirection[slicingDimOfArray]*dy*(that.nii.sizes[slicingDimOfArray]-1) ) }, mouseup: function(){ } }); // zoom slider attachMouseSlider(layoutbar.$slidezoom, { mousedown: function() { return { startzoomFac: that.zoomFac, startBox: that.mosaicview.clipratio, currentpos: getCanvasCoordinates(getWorldPosition()), } }, mousemove:function(ev,dx,dy,mousedownvar, lastdx, lastdy) { if (gl_enabled) { var zoominc = 1 - lastdy*0.001; var maxex = that.computeMaxExtentFac() that.gl.camera.inertialRadiusOffset -= maxex * (1 - zoominc); if (isNaN(that.gl.camera.inertialRadiusOffset)) that.gl.camera.inertialRadiusOffset = 1; that.gl.sync3DViews(that.gl.camera.inertialAlphaOffset,that.gl.camera.inertialBetaOffset, that.gl.camera.inertialPanningX,that.gl.camera.inertialPanningY,that.gl.camera.inertialRadiusOffset ); that.gl.activateRenderLoop(); setTimeout(that.gl.setQuality,350); } else if (that.mosaicview.active) { var sbox = mousedownvar.startBox; var cpos = mousedownvar.currentpos; var zoomy = 1+0.1*dy; sbox[0] = (sbox[0]-cpos.x_norm)*zoomy + cpos.x_norm; sbox[2] = (sbox[2]-cpos.x_norm)*zoomy + cpos.x_norm; sbox[1] = (sbox[1]-cpos.y_norm)*zoomy + cpos.y_norm; sbox[3] = (sbox[3]-cpos.y_norm)*zoomy + cpos.y_norm; if (sbox[0]<0) sbox[0] = 0; if (sbox[1]<0) sbox[1] = 0; if (sbox[2]>1) sbox[2] = 1; if (sbox[3]>1) sbox[3] = 1; if (sbox[2]-sbox[0] < 0.0001 | sbox[3]-sbox[1] < 0.0001 ) { sbox = [0,0,1,1]; alertify.error("are you nuts") } that.mosaicview.clipratio = sbox; if (KViewer.mainViewport != -1) signalhandler.send("mosaic_changelayout",that.mosaicview); else { setCanvasLayout(); drawHairCross(); } } else { var zoominc = 1 - lastdy*0.01; $(".markerpoint,.markerruler").css('display','none') if (worldLockedToMaster & master.globalCoordinates & !ev.shiftKey & !that.isFlatMap) { signalhandler.send("setZoom", zoominc ); signalhandler.send("positionChange", {nosliceupdate:true},that.positionChanger); } else { setZoom(zoominc); signalhandler.send("positionChange", {nosliceupdate:true},that.positionChanger); } } return true; }, mouseup: function(){ signalhandler.send("positionChange", {},that.positionChanger); } }, {hideCurrentval:true} ); layoutbar.attach(layoutbar.$slideslices) layoutbar.attach(layoutbar.$center); layoutbar.attach(layoutbar.$slidezoom) layoutbar.$resetzoom = $("<span class='KViewPort_tool_layout'> <i class='fa fa-reply fa-1x'></i> </span>"); layoutbar.$resetzoom.mousedown(function(ev){ var p = niiOriginal.centerWorld if (that.isFlatMap) { customPoint = p; p = mapFlatMapCoordinate(p) } KViewer.resetCrossHair(ev,p) }) layoutbar.attach(layoutbar.$resetzoom) layoutbar.$zoomin.on("mousedown", function(e) { if (layoutbar.$zoomin.iid != -1) clearInterval(layoutbar.$zoomin.iid); var maxex = that.computeMaxExtentFac() layoutbar.$zoomin.fac = 1.002; if (gl_enabled) { layoutbar.$zoomin.iid = setInterval(function() { that.gl.camera.inertialRadiusOffset -= maxex * (1 - layoutbar.$zoomin.fac); if (isNaN(that.gl.camera.inertialRadiusOffset)) that.gl.camera.inertialRadiusOffset = 1; that.gl.activateRenderLoop(); that.gl.setQuality() }, 0); } else if (that.mosaicview.active) { var amount = 1; that.mosaicview.zoom += ((amount > 0) ? -1 : 1) * 0.3 * scrollSpeed; if (that.mosaicview.zoom > 1) that.mosaicview.zoom = 1; setCanvasLayout(); drawHairCross(); } else { layoutbar.$zoomin.iid = setInterval(function() { $(".markerpoint,.markerruler").css('display','none') signalhandler.send("setZoom", layoutbar.$zoomin.fac); signalhandler.send("positionChange", {nosliceupdate:true},that.positionChanger); if (layoutbar.$zoomin.fac < 1.01) layoutbar.$zoomin.fac += 0.0002; }, 0); } }); layoutbar.$zoomin.on("mouseup mouseleave", function(e) { clearInterval(layoutbar.$zoomin.iid); layoutbar.$zoomin.iid = -1; }); layoutbar.$zoomout.on("mousedown", function(e) { if (layoutbar.$zoomout.iid != -1) clearInterval(layoutbar.$zoomin.iid); var maxex = that.computeMaxExtentFac() layoutbar.$zoomout.fac = 0.998; if (gl_enabled) { layoutbar.$zoomout.iid = setInterval(function() { that.gl.camera.inertialRadiusOffset += maxex * (1 - layoutbar.$zoomin.fac); if (isNaN(that.gl.camera.inertialRadiusOffset)) that.gl.camera.inertialRadiusOffset = 1; that.gl.activateRenderLoop(); that.gl.setQuality() }, 0); } else if (that.mosaicview.active) { var amount = -1; that.mosaicview.zoom += ((amount > 0) ? -1 : 1) * 0.3 * scrollSpeed; if (that.mosaicview.zoom > 1) that.mosaicview.zoom = 1; if (KViewer.mainViewport != -1) signalhandler.send("mosaic_changelayout",that.mosaicview); else { setCanvasLayout(); drawHairCross(); } } else { layoutbar.$zoomout.iid = setInterval(function() { $(".markerpoint,.markerruler").css('display','none') signalhandler.send("setZoom", layoutbar.$zoomout.fac); signalhandler.send("positionChange", {nosliceupdate:true},that.positionChanger); if (layoutbar.$zoomout.fac > 0.99) layoutbar.$zoomout.fac -= 0.0002; }, 0); } }); layoutbar.$zoomout.on("mouseup mouseleave", function(e) { clearInterval(layoutbar.$zoomout.iid); }); layoutbar.$zoomin.hide(); layoutbar.$zoomout.hide(); layoutbar.$moszoomin = $("<span class='KViewPort_tool_layout'> <i class='fa fa-plus'></i> </span>").hide().click( function(e) { var amount = -1; that.mosaicview.nx_cont += ((amount > 0) ? -1 : 1); if (that.mosaicview.nx_cont < 2) that.mosaicview.nx_cont = 2; that.mosaicview.nx = Math.round(that.mosaicview.nx_cont); if (KViewer.mainViewport != -1) signalhandler.send("mosaic_changelayout",that.mosaicview); else { setCanvasLayout(); drawHairCross(); } }); layoutbar.$moszoomout = $("<span class='KViewPort_tool_layout'> <i class='fa fa-minus'></i> </span>").hide().click( function(e) { var amount = 1; that.mosaicview.nx_cont += ((amount > 0) ? -1 : 1); if (that.mosaicview.nx_cont < 2) that.mosaicview.nx_cont = 2; that.mosaicview.nx = Math.round(that.mosaicview.nx_cont); if (KViewer.mainViewport != -1) signalhandler.send("mosaic_changelayout",that.mosaicview); else { setCanvasLayout(); drawHairCross(); } }); layoutbar.$leftrot = $("<span class='KViewPort_tool_layout'> <i class='fa fa-rotate-left'></i> </span>").hide(); layoutbar.$rightrot = $("<span class='KViewPort_tool_layout'> <i class='fa fa-rotate-right'></i> </span>").hide(); function ani3D(e, dir) { layoutbar.$rightrot.removeClass('KViewPort_tool_enabled'); layoutbar.$leftrot.removeClass('KViewPort_tool_enabled'); if (that.gl.animate3D(dir)) $(e).addClass('KViewPort_tool_enabled'); } function setGLprops(props) { var cid = setInterval(tryit,300) var cnt = 0; function tryit() { cnt++; if (that.gl != undefined) { that.gl.setprops(props) clearInterval(cid) } else if (cnt > 10) clearInterval(cid) } } that.setGLprops = setGLprops layoutbar.$leftrot.click(function() { ani3D(this, +1) }); layoutbar.$rightrot.click(function() { ani3D(this, -1) }); layoutbar.attach(layoutbar.$moszoomin) .attach(layoutbar.$moszoomout) .attach(layoutbar.$rightrot) .attach(layoutbar.$leftrot); layoutbar.showLayout3D = function() { layoutbar.$leftrot.show(); layoutbar.$rightrot.show(); if ( layoutbar.$shortcut3d) layoutbar.$shortcut3d.text("2D"); layoutbar.$slicing.hide(); layoutbar.$slideslices.hide(); layoutbar.$center.hide(); } layoutbar.hideLayout3D = function() { layoutbar.$leftrot.hide(); layoutbar.$rightrot.hide(); if ( layoutbar.$shortcut3d) { layoutbar.$shortcut3d.show(); layoutbar.$shortcut3d.text("3D"); } layoutbar.$slicing.show(); layoutbar.$slideslices.show(); layoutbar.$center.show(); } // this should be implemented at another place ( in roiPanel) var ROIadder = function(_that) { return KContextMenu( function() { var upperadder var loweradder var $menu = $("<ul class='menu_context small'>") .append($("<hr width='100%'> ")) .append($("<span> &nbsp <i class='fa leftaligned fa-pencil-square-o fa-1x'></i> ROI </span>")) .append($("<hr width='100%'> ")) .append($("<li onchoice='empty' > create empty </li>")) .append(upperadder= $("<li onchoice='upper' > larger than lower limit </li>")) .append(loweradder=$("<li onchoice='lower' > lower than lower limit </li>")) .append($("<hr width='100%'> ")) .append($("<span> &nbsp <i class='fa leftaligned fa-shopping-basket fa-1x'></i> Miscellaneous </span>")) .append($("<hr width='100%'> ")) var currentid = _that.currentFileID; var matrices_available = []; if (that.currentFileID != currentid) matrices_available.push({n:that.currentFilename,id:that.currentFileID}) for (var i = 0; i < that.ROIs.length;i++) if (that.ROIs[i].roi.fileID != currentid) matrices_available.push({id:that.ROIs[i].roi.fileID,n:that.ROIs[i].roi.filename}) for (var i = 0; i < that.overlays.length;i++) if (that.overlays[i].currentFileID != currentid) matrices_available.push({n:that.overlays[i].currentFilename,id:that.overlays[i].currentFileID}) if (matrices_available.length>0) { var str_upper = ""; var str_lower = ""; for (var i = 0; i < matrices_available.length;i++) { str_upper += "<li onchoice='upper_"+ matrices_available[i].id +"'> " + matrices_available[i].n + " </li> " str_lower += "<li onchoice='lower_"+ matrices_available[i].id +"'> " + matrices_available[i].n + " </li> " } upperadder.append($(" <ul> " + str_upper +" </ul>" )) loweradder.append($(" <ul> " + str_lower +" </ul>" )) } if (_that.nii.sizes[3]%3 == 0) { var sel = _that.showcolored ? 'check-' : ''; var type = _that.showcolored_type; $menu.append($("<li onchoice='rgbinterpret' > RGB interpret <i class='fa fa-caret-right'></i> <ul> " + "<li onchoice='rgbinterpret' > colored <i onchoice='lock' class='fa fa-"+sel+"square-o'></i> </li>" + "<li onchoice='type_rgbinterpret_raw' > raw <i onchoice='lock' class='fa fa-"+((type=="raw") ? 'check-' : '')+"circle-o'></i> </li>" + "<li onchoice='type_rgbinterpret_RGB' > RGB <i onchoice='lock' class='fa fa-"+((type=="RGB") ? 'check-' : '')+"circle-o'></i> </li>" + "<li onchoice='type_rgbinterpret_BRG' > BRG <i onchoice='lock' class='fa fa-"+((type=="BRG") ? 'check-' : '')+"circle-o'></i> </li>" + "<li onchoice='type_rgbinterpret_GBR' > GBR <i onchoice='lock' class='fa fa-"+((type=="GBR") ? 'check-' : '')+"circle-o'></i> </li>" + "<li onchoice='type_rgbinterpret_GRB' > GRB <i onchoice='lock' class='fa fa-"+((type=="GRB") ? 'check-' : '')+"circle-o'></i> </li>" + "<li onchoice='type_rgbinterpret_SOS' > SOS <i onchoice='lock' class='fa fa-"+((type=="SOS") ? 'check-' : '')+"circle-o'></i> </li>")); } if (_that.refSurfView != undefined) { var showview = ""; if (!_that.refSurfView.toolbarAttached) showview= " <i onchoice='showisoview' class='fa button' style='right:30px;'>show view</i> " $menu.append($("<li onchoice='iso' > remove isosurface "+showview+" </li>")); } else $menu.append($("<li onchoice='iso' > create isosurface </li>")); if (_that.type != "mainview") { if (_that.outlines == undefined) $menu.append($("<li onchoice='outline' > show contours </li>")); else { $menu.append($("<li onchoice='outline' > hide contours </li>")); $menu.append($("<li onchoice='contcol' > > contour color </li>")); } } if (_that.nii.sizes[3]%3 == 0) $menu.append($("<li onchoice='tracking' >create fiber tracking </li>")); $menu.append($("<li onchoice='refetch' > refetch file </li>")); $menu.append($("<hr width='100%'> ")) $menu.append($("<li onchoice='reslice' > reformat/reslice image </li>")); if (KViewer.reorientationMatrix.notID) $menu.append($("<li onchoice='burnin' > burnin current affine </li>")); $menu.append($("<li onchoice='download_header_info' > download header info </li>")); $menu.append($("<li onchoice='centermatrix' > center matrix to current position </li>")); var ROIs = KViewer.roiTool.ROIs var rois = Object.keys(ROIs); if (rois.length > 0) { var $submenu = $("<ul> </ul>") var $item = $("<li onchoice='...' >crop/mask<i onchoice='lock' class='fa fa-caret-right'></i>").appendTo($menu) $item.append($submenu) for (var k = 0; k < rois.length;k++) $submenu.append($("<li onchoice='mask_ROI_"+rois[k]+"' >"+ROIs[rois[k]].filename+" </li>")); } if (_that.content && _that.content.refvisit_tck) $menu.append($("<li onchoice='unlinktck' > unlink fiber visits </li>")); return $menu; }, function(str, ev) { function arrived(fobj) { master.iterateMedViewers(function(m) { if (_that.currentFileID == m.currentFileID) m.setContent(fobj, {intent: { ROI: true } }); else for (var k = 0; k < m.overlays.length; k++) { if (_that.currentFileID == m.overlays[k].currentFileID) { m.setContent(fobj, {intent: {ROI: true}}); return; } } }); that.ROIs[that.ROIs.length - 1].makeCurrent(); } if (str == undefined) return; if (str == "unlinktck") { unlinktck(_that) } else if (str.substring(0,5) == "upper" | str.substring(0,5) == "lower" ) { var typ = str.substring(0,5); if (str.length == 5) master.roiTool.pushROI(_that.currentFileID, "mask_"+ _that.currentFilename, typ + _that.histoManager.clim[0], arrived); else { var id = str.substring(6) $(document.body).addClass("wait"); setTimeout( function() { master.roiTool.pushROI(id, "mask_"+ _that.currentFilename,undefined, function(fobj) { var thres = _that.histoManager.clim[0]; var eqfun; if (typ == "lower") eqfun = function(x) { return x < thres; } else eqfun = function(x) { return x > thres; } var nii = _that.nii; var roi = fobj.content; var offset = 0; if (nii.currentTimePoint) offset = nii.currentTimePoint.t * nii.sizes[0] * nii.sizes[1] * nii.sizes[2] ; var A = (math.multiply(math.inv(nii.edges), roi.edges))._data; for (var z = 0; z < roi.sizes[2]; z++) for (var y = 0; y < roi.sizes[1]; y++) for (var x = 0; x < roi.sizes[0]; x++) { if (eqfun(trilinInterp(nii, x, y, z, A, offset))) roi.data[roi.sizes[1] * roi.sizes[0] * z + roi.sizes[0] * y + x] = 1; } arrived(fobj) $(document.body).removeClass("wait"); } ); },0); } } else if (str == "empty") master.roiTool.pushROI(_that.currentFileID, "mask_untitled", undefined, arrived); else if (str == "iso") that.attachSurfaceRef(_that,_that.content); else if (str == 'rgbinterpret') { _that.showcolored = !_that.showcolored; signalhandler.send("updateImage",{id:_that.currentFileID}); } else if (str.substring(0,17) == 'type_rgbinterpret') { _that.showcolored_type = str.substring(18); signalhandler.send("updateImage",{id:_that.currentFileID}); } else if (str == "showisoview") { if (_that.refSurfView && !_that.refSurfView.toolbarAttached) { ev.preventDefault(); ev.stopImmediatePropagation(); that.toolbar.append(_that.refSurfView.divs,'surface') _that.refSurfView.toolbarAttached = true; } } else if (str == "tracking") { if (that.isGLenabled()) createfibview() else toggle3D(undefined,createfibview); function createfibview() { var filename = _that.currentFilename.replace(".nii","").replace(".gz","") + ".tck"; var imageStruct = { fileinfo: { patients_id: that.currentFileinfo.patients_id, studies_id: that.currentFileinfo.studies_id }, filename:filename,content:{tracts:[ ]} } ; var fv = master.obj3dTool.createFiberView(imageStruct,that,{ dirvolref: _that,isParentView:true }); that.objects3D.push(fv); } } else if (str == "outline") { var contvis = _that.outlines == undefined; if (!ev.shiftKey) { var ev_ = ev; master.iterateMedViewers(function(m) { for (var k = 0; k < m.overlays.length; k++) if (_that.currentFileID == m.overlays[k].currentFileID) { m.overlays[k].setOutlines(contvis,ev_) ev_ = undefined break; } }); } else _that.setOutlines(contvis,ev) } else if (str == "refetch") { KViewer.dataManager.refetchFile(_that.currentFileinfo, that.viewport.progressSpinner) } else if (str == "reslice") { alertify.prompt("New resolution of image in mm:", function(e, str) { if (e) { var fac = eval(str); var fi = KViewer.dataManager.getFile(_that.currentFileID) var vsz = fi.content.voxSize resliceNifti(fi,[fac[0]/vsz[0],fac[1]/vsz[1],fac[2]/vsz[2]]); var sp = fi.filename.split(".") sp[0] = sp[0] + '_reformated'; fi.filename = sp.join("."); if (fi.fileinfo && fi.fileinfo.Filename) fi.fileinfo.Filename = fi.filename; fi.editable = true; fi.modified = true; KViewer.cacheManager.update(); KViewer.setViewPortLayout() } },"[2,2,2]"); } else if (str == "burnin") { var fi = KViewer.dataManager.getFile(_that.currentFileID) resliceNifti_affine(fi,(KViewer.reorientationMatrix.matrix)); var sp = fi.filename.split(".") sp[0] = sp[0] + '_reformated'; fi.filename = sp.join("."); if (fi.fileinfo && fi.fileinfo.Filename) fi.fileinfo.Filename = fi.filename; fi.editable = true; fi.modified = true; KViewer.navigationTool.resetTransform(); KViewer.cacheManager.update(); KViewer.setViewPortLayout() } else if (str == "centermatrix") { if (Object.keys(KViewer.navigationTool.movingObjs).length > 0) alertify.confirm("There are already moving images defined in the navigation. When you proceed, all navigation information will be discarded.", function(e) { if (e) centermatrix() }) else centermatrix(); function centermatrix() { var fi = KViewer.dataManager.getFile(_that.currentFileID) for (var k in KViewer.navigationTool.movingObjs) delete KViewer.navigationTool.movingObjs[k]; KViewer.navigationTool.movingObjs[fi.fileID] = fi; KViewer.navigationTool.updateMoving(); var csz = fi.content.sizes.slice(0,3).map((x)=>x*0.5-0.5).concat([1]) var center = kmath.multiply(fi.content.edges, csz) var dif = kmath.add(KViewer.currentPoint,center,-1); KViewer.reorientationMatrix.matrix._data[0][3] = -dif._data[0]; KViewer.reorientationMatrix.matrix._data[1][3] = -dif._data[1]; KViewer.reorientationMatrix.matrix._data[2][3] = -dif._data[2]; signalhandler.send("positionChange") } } else if (str == "download_header_info") { var fi = _that.currentFileinfo var nii = _that.nii var hdr = {edges:nii.edges._data, voxSize:nii.voxSize, sizes:nii.sizes, extension:nii.extension} initiateDownload(JSON.stringify(hdr), fi.Filename.replace(".gz","").replace(".nii","") + "_header.json"); } else if (str.substring(0,9) == "mask_ROI_") { var roiid = str.substring(9); var fi = KViewer.dataManager.getFile(_that.currentFileID) var roi = KViewer.dataManager.getFile(roiid) maskContrastWithROI(fi,roi) signalhandler.send("updateImage", { id: fi.fileID, }); fi.editable = true; fi.modified = true; KViewer.cacheManager.update(); function maskContrastWithROI(cobj,roiobj) { var nii = cobj.content var roi = roiobj.content; roi.A = (math.multiply(math.inv(roi.edges), nii.edges))._data; for (var k = 0;k < nii.sizes[3];k++) for (var z = 0; z < nii.sizes[2]; z++) for (var y = 0; y < nii.sizes[1]; y++) for (var x = 0; x < nii.sizes[0]; x++) { var v = trilinInterp(roi, x, y, z, roi.A, 0); nii.data[nii.widheidep*k + nii.sizes[1] * nii.sizes[0] * z + nii.sizes[0] * y + x] *= v; } } } else if (str == "contcol") { _that.chooseContColor(ev); } }); } function unlinktck(_that) { if (_that.content.refvisit_tck.visitworker != undefined) { _that.content.refvisit_tck.visitworker.kill(); _that.content.refvisit_tck.visitworker = undefined; } if (_that.content.refvisit_tck.visitworker_terms != undefined) { _that.content.refvisit_tck.visitworker_terms.kill(); _that.content.refvisit_tck.visitworker_terms = undefined; } _that.content.refvisit_tck = undefined; } that.unlinktck = unlinktck; that.quivers = []; that.addQuiver = function(histoobj) { for (var k = 0; k < that.quivers.length;k++) { if (that.quivers[k] == histoobj) return; } that.quivers.push(histoobj); } that.removeQuiver = function(histoobj) { for (var k = 0; k < that.quivers.length;k++) { if (that.quivers[k] == histoobj) { that.quivers.splice(k,1); return; } } } that.addAsROIMenu = ROIadder(that); /* this was used as a roi adder per viewport var toolbarRoi = {}; toolbarRoi.$container = $("<div class='KViewPort_roiAdder' style='position:relative;right:0px;'>add Roi</div>").appendTo(that.toolbar.$container).click(function(ev){return false;}) .hide(); toolbarRoi.$addroi = $("<div class='KViewPort_tool'> <i class='fa fa-plus fa-1x'> </div>").appendTo(toolbarRoi.$container ) .appendTooltip("create new roi from this viewport image").click( function(){master.roiTool.createEmptyRoi(that, 'untitled');} ); */ // old: allow creation of roi here toolbar.$addroi = $("<div class='KViewPort_tool'> <i class='fa fa-cog fa-1x'> </div>").click(that.addAsROIMenu); //toolbar.$addroi = $("<div class='KViewPort_tool'> <i class='fa fa-pencil fa-1x'> </div>") //.appendTooltip("roitool_open").click(function() { // master.roiTool.show() //}); toolbar.$mainViewportSelector = $("<div myid='KViewPort_tool_toggleMainViewport' class='KViewPort_tool'><i class='fa fa-maxcdn fa-1x'></i></div>") .appendTooltip("masterviewport").click(function() { master.toggleMainViewport(viewport.viewPortID); }); toolbar.$movie = $("<div class='KViewPort_movie_tool'><i class='fa fa-play fa-1x'></i></div>").click(function() { toggleMovie(this); }); toolbar.$movie.hide(); toolbar.attach(toolbar.$addroi).attach(toolbar.$mainViewportSelector).attach(toolbar.$movie); /************************* movie stuff *********************/ that.movieSpeedFPS = 5; function changemoviespeed() { toggleMovie(); if(that.movieGlobalMode) { master.iterateMedViewers(function(m) { if (m.nii !=undefined && m.$timediv.maxt > 1 & m.movieGlobalMode) { m.$timeinput_fps.val( $timeinput_fps.val() ); m.movieSpeedFPS = $timeinput_fps.val(); } }); } else { that.movieSpeedFPS = $timeinput_fps.val(); } toggleMovie(); } var $timeinput_fps = $("<input class='KViewPort_tool' style='' type='' min=1 max=100000 value=" + that.movieSpeedFPS + " />") .appendTooltip("Movie Speed (frames per second") .on('change input', changemoviespeed); that.$timeinput_fps = $timeinput_fps; /* movie can be played - globally: link all viewports (default), given by master.currentTimePointGlobal, master.movieIsPlayedGlobal - individually */ var $setMovieGlobalMode = $("<div class='KViewPort_movie_tool'><i class='fa fa-link fa-1x'></i></div>").click( setMovieGlobalMode ); that.movieGlobalMode = 1; function setMovieGlobalMode(state) { // do not allow to change mode during play, otherwise will be a mess if(movieIsPlayed | master.movie.isPlayed) return false that.movieGlobalMode = !that.movieGlobalMode; if(!that.movieGlobalMode) { $setMovieGlobalMode.css('background', 'red'); } else { $setMovieGlobalMode.css('background', ''); } } var $timeinput = $("<input class='KViewPort_tool KViewPort_tool_movie_slider' type='range' min=0 max=100 value=0>"); var $timeCurrent = $("<span class='KViewPort_movie_tool'>0</span>"); var $timediv = $("<div class='KViewPort_toolbar KTimeRangeSlider'> </div>").appendTo($container) .append($timeCurrent).append($timeinput).append(toolbar.$movie).append($timeinput_fps).append($setMovieGlobalMode) .hide(); that.$timediv = $timediv; that.$timediv.$timeinput = $timeinput; // this is called when new image is loaded $timediv.update = function() { var maxt = 1; if (that.nii != undefined && that.nii.numTimePoints > 1) maxt = that.nii.numTimePoints; for (var k = 0; k < that.overlays.length; k++) if (that.overlays[k].nii.numTimePoints > maxt) maxt = that.overlays[k].nii.numTimePoints; for (var k = 0; k < that.ROIs.length; k++) if (that.ROIs[k].nii.numTimePoints > maxt) maxt = that.ROIs[k].nii.numTimePoints; if (maxt > 1) { $timediv.maxt = maxt; that.toolbar.$movie.show(); $timediv.show(); $timeinput.attr("max", maxt-1 ); that.setMovieState(movieIsPlayed | master.movie.isPlayed); } else { $timediv.maxt = 1; that.toolbar.$movie.hide(); $timediv.hide(); } } KMouseSlider($timeinput_fps, {min:1, incrementPerPixel:0.1}); $timeinput.on('change input', function(){setCurrentTimePoint( $(this).val() ); } ); //$timeCurrent.on('mousewheel', timeinputwheel) //$timediv.on('mousewheel', timeinputwheel) if (/Firefox/i.test(navigator.userAgent)) $timediv.get(0).addEventListener("DOMMouseScroll", timeinputwheel, false); else $timediv.get(0).addEventListener("mousewheel", timeinputwheel, false); function timeinputwheel(e) { if(e.wheelDelta || -e.detail) var amount = (e.wheelDelta || -e.detail) > 0 ?1:-1; else var amount = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0 ?1:-1; var newval = parseInt($timeinput.val()) + amount; if(newval >= 0) { setCurrentTimePoint(newval,e) } e.preventDefault(); e.stopPropagation(); return false; } // set the current time global/local from gui or from an iteration loop function setCurrentTimePoint(val,e) { var global = that.movieGlobalMode; if (e != undefined && e.shiftKey) global = false; if (global) { master.movie.currentTimePoint = val; master.iterateMedViewers(function(m) { if (m.nii !=undefined & m.movieGlobalMode & global) { m.updateCurrentTimePoint(val); } }); } else { that.updateCurrentTimePoint(val); } } that.updateCurrentTimePoint = function(val) { var ovls = that.overlays; for (var k = 0; k < that.objects3D.length;k++) if (that.objects3D[k].overlays && that.objects3D[k].overlays.length > 0) ovls = ovls.concat(that.objects3D[k].overlays) for (var k = 0; k < ovls.length; k++) { var xnii = ovls[k].nii; if (xnii.numTimePoints > 1 && xnii.numTimePoints >= val) { xnii.currentTimePoint.t = val; ovls