Application.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. IPE.app = {};
  2. IPE.helper = {};
  3. IPE.interceptors = {};
  4. String.prototype.endsWith = function(suffix) {
  5. return this.indexOf(suffix, this.length - suffix.length) !== -1;
  6. };
  7. Array.prototype.last = function() {
  8. return this[this.length-1];
  9. }
  10. IPE.app = {
  11. init : function(config) {
  12. var headerHeight = $('header').height();
  13. if($(window).height() < 500) {
  14. $("body").animate({ scrollTop: headerHeight }, "slow");
  15. }
  16. $.each(IPE.interceptors, function(index, interceptor) {
  17. interceptor.init();
  18. });
  19. Globals.init();
  20. IPE.app.initializeHelper();
  21. IPE.app.bindEvents();
  22. IPE.app.initData();
  23. tempRenderer = new THREE.WebGLRenderer();
  24. maximumTextureSize = tempRenderer.context.getParameter(tempRenderer.context.MAX_TEXTURE_SIZE);
  25. // we have to take an power of 2 less
  26. maximumTextureSize /= 2;
  27. if(config.defaultSize > maximumTextureSize) {
  28. config.defaultSize = maximumTextureSize;
  29. }
  30. // Getting info file
  31. $.ajax({
  32. url: infoUrl + config.defaultSize,
  33. success: function (data) {
  34. textureInfo = data;
  35. originalSizeArray[0] = textureInfo.originalSize.sizex;
  36. originalSizeArray[1] = textureInfo.originalSize.sizey;
  37. originalSizeArray[2] = textureInfo.originalSize.sizez;
  38. imgInfo = data.info;
  39. currentVolumeDimension.xmin = 0;
  40. currentVolumeDimension.xmax = textureInfo.originalSize.sizex;
  41. currentVolumeDimension.ymin = 0;
  42. currentVolumeDimension.ymax = textureInfo.originalSize.sizey;
  43. currentVolumeDimension.zmin = imgInfo.imgMin;
  44. currentVolumeDimension.zmax = imgInfo.imgMax;
  45. // downloading first image and starting
  46. helper.downloadImage(spriteUrl + textureInfo.sprites[0][0].$oid, 0, 0, true);
  47. $(document).trigger('basicsReady');
  48. },
  49. dataType: 'json'
  50. });
  51. container = document.getElementById( 'container' );
  52. $container = $(container);
  53. containerHeader = document.getElementById( 'container-header' );
  54. $containerHeader = $(containerHeader);
  55. containerOverview = document.getElementById('container-overview');
  56. $containerOverview = $(containerOverview);
  57. statsHelper = new StatsHelper($containerHeader.children('#container-stats'));
  58. // until now, it has to be initialized here, needs a new internal structure
  59. zoomHelper = new ZoomHelper();
  60. $(window).on('scroll', function(e) {
  61. if($(this).scrollTop() >= headerHeight) {
  62. $container.css('position', 'relative');
  63. $container.css('top', $(this).scrollTop() - headerHeight);
  64. } else {
  65. $container.css('top', 0);
  66. }
  67. });
  68. },
  69. initializeHelper: function() {
  70. helper = new Helper();
  71. geometryHelper = new GeometryHelper();
  72. stepHelper = new StepHelper();
  73. overviewHelper = new OverviewHelper();
  74. transferHelper = new TransferHelper();
  75. opacityPlotter = new OpacityPlotter();
  76. },
  77. initData: function() {
  78. volumeId = $('#volumeId').val();
  79. $resSpan = $('span#currentRes');
  80. volumeUrl = IPE.util.buildUrl('volumes/' + volumeId + '/');
  81. infoUrl = volumeUrl + 'texture-info/';
  82. spriteUrl = volumeUrl + 'sprite/';
  83. waitDiv = $('div#wait');
  84. helper.initializeShaders(IPE.util.buildUrl('static/shaders/three-shader.vert'), function(script) {
  85. vertexShader = script
  86. });
  87. helper.initializeShaders(IPE.util.buildUrl('static/shaders/three-shader-simple.frag'), function(script) {
  88. fragmentSimleShader = script
  89. });
  90. helper.initializeShaders(IPE.util.buildUrl('static/shaders/three-shader.frag'), function(script) {
  91. fragmentShader = script
  92. });
  93. },
  94. bindEvents : function() {
  95. $(document).on('firstImageOnLoad',function (e, firstImageParams){
  96. initTextures(imgInfo, firstImageParams, true);
  97. initFrameControls();
  98. stepHelper.initStepControls();
  99. initSliders();
  100. });
  101. $(document).on('imageOnLoad', function(e, imageParams) {
  102. initTextures(imgInfo, imageParams, false);
  103. if(useDownloadedTextureImmediately) {
  104. updateTexture();
  105. useDownloadedTextureImmediately = false;
  106. updateFrameControls();
  107. }
  108. });
  109. $(document).on('firstFrameSpritesCompleted', function() {
  110. init();
  111. addResolutionLinks();
  112. overviewHelper.initOverview(containerOverview);
  113. animate();
  114. });
  115. showPopup = false;
  116. $('#save-canvas').click(function(e, params) {
  117. if(params != undefined && params.source != undefined && params.source == 'animate-function') {
  118. window.open(params.imageUrl);
  119. return false;
  120. } else {
  121. saveImage = true;
  122. return false;
  123. }
  124. });
  125. $(window).on('resize', function() {
  126. var rendererSizeHolder = calculateWidthHeight();
  127. width = rendererSizeHolder.width.px;
  128. height = rendererSizeHolder.height.px;
  129. cameraRTT.aspect = width / height;
  130. cameraRTT.updateProjectionMatrix();
  131. camera.aspect = width / height;
  132. camera.updateProjectionMatrix();
  133. renderer.setSize( width, height );
  134. renderer.domElement.style.width = rendererSizeHolder.width.percent + '%';
  135. renderer.domElement.style.height = rendererSizeHolder.height.percent + '%';
  136. });
  137. $resolutionLinks.on('click', 'a', function(e) {
  138. e.preventDefault();
  139. e.stopPropagation();
  140. var $this = $(this);
  141. if($this.attr('href') == undefined) {
  142. return false;
  143. }
  144. requestedSize = $this.attr('data');
  145. $('.res-link').each(function(index, value) {
  146. var $value = $(value);
  147. $value.attr('href', '#');
  148. });
  149. $this.removeAttr('href');
  150. $.ajax({
  151. // todo test after remove of sync flag
  152. url: infoUrl + requestedSize,
  153. success: function (data) {
  154. framesDownloaded = 0;
  155. textures = {};
  156. currentTexture = 0;
  157. textureInfo = data;
  158. imgInfo = data.info;
  159. imgMin = imgInfo.imgMin;
  160. imgMax = imgInfo.imgMax;
  161. useDownloadedTextureImmediately = true;
  162. helper.downloadImage(spriteUrl + textureInfo.sprites[0][0].$oid, 0, 0, false);
  163. $resSpan.text(requestedSize);
  164. if($('input#hide-content-small-devices').is(':visible')) {
  165. $('input#hide-content-small-devices').trigger('click');
  166. }
  167. },
  168. dataType: 'json'
  169. });
  170. return false;
  171. });
  172. $('div.controls').on('click', function() {
  173. var $this = $(this),
  174. bottomControlsContainer = $('div#bottom-controls-container'),
  175. bottomControls = $('div#bottom-controls'),
  176. filledById = '',
  177. thisControlHolder = null;
  178. filledById = hideBottomControlsContainer();
  179. if(filledById === $this.attr('id')) {
  180. return;
  181. }
  182. thisControlHolder = $this.children('.control-holder')[0];
  183. thisControlHolder = $(thisControlHolder);
  184. bottomControls.append(thisControlHolder.children());
  185. bottomControls.attr('filledBy', $this.attr('id'));
  186. bottomControlsContainer.removeClass('hidden');
  187. // inform, that it is showed
  188. $this.trigger('controlsShowed');
  189. });
  190. $('input#hide-bottom-controls-container').on('click', function() {
  191. hideBottomControlsContainer();
  192. });
  193. $('div#menu-buttons-small-devices input').on('click', function() {
  194. var $this = $(this),
  195. target = $this.attr('data'),
  196. $target = $('#' + target),
  197. $overlay = $('div#overlay-small-devices'),
  198. $content = $('div#content-small-devices');
  199. $overlay.attr('source', target);
  200. $content.append($target.children());
  201. $overlay.show();
  202. });
  203. $('input#hide-content-small-devices').on('click', function() {
  204. var $overlay = $('div#overlay-small-devices'),
  205. $content = $('div#content-small-devices'),
  206. source = $overlay.attr('source'),
  207. $source = $('#' + source);
  208. $overlay.hide();
  209. $overlay.attr('source', '');
  210. $source.append($content.children());
  211. });
  212. var buttonAdvCons = $('input#show-adv-con');
  213. buttonAdvCons.on('click', function() {
  214. var advCons = $('div#advanced-controls');
  215. if(advCons.hasClass('hidden')) {
  216. advCons.removeClass('hidden');
  217. buttonAdvCons.val('hide adv cons');
  218. } else {
  219. advCons.addClass('hidden');
  220. buttonAdvCons.val('show adv cons');
  221. }
  222. });
  223. $(document).on('initFinished', function() {
  224. $canvas.addClass('context-menu');
  225. $.contextMenu({
  226. selector: 'canvas.context-menu',
  227. callback: function(key, options) {
  228. if(key === 'save') {
  229. saveImage = true;
  230. }
  231. },
  232. items: {
  233. "save": {name: "Open image in new tab"}
  234. }
  235. });
  236. });
  237. $('input#adjust-isodata-thresholding-bottom-controls-container').on('click', function() {
  238. console.log(textureInfo.info.thresholdIndex_isodata);
  239. GenericSlider.setPosSlider(
  240. slider = $( "#gray-slider" ),
  241. sliderInputs = $('input.gray'),
  242. minGray,
  243. textureInfo.info.thresholdIndex_isodata
  244. );
  245. $(document).trigger('opacityBordersChanged', { minGray: minGray, maxGray: textureInfo.info.thresholdIndex_isodata});
  246. });
  247. $('input#adjust-otsu-thresholding-bottom-controls-container').on('click', function() {
  248. console.log(textureInfo.info.thresholdIndex_otsu);
  249. GenericSlider.setPosSlider(
  250. slider = $( "#gray-slider" ),
  251. sliderInputs = $('input.gray'),
  252. minGray,
  253. textureInfo.info.thresholdIndex_otsu
  254. );
  255. $(document).trigger('opacityBordersChanged', { minGray: minGray, maxGray: textureInfo.info.thresholdIndex_otsu});
  256. });
  257. $('input#adjust-yen-thresholding-bottom-controls-container').on('click', function() {
  258. console.log(textureInfo.info.thresholdIndex_yen);
  259. GenericSlider.setPosSlider(
  260. slider = $( "#gray-slider" ),
  261. sliderInputs = $('input.gray'),
  262. minGray,
  263. textureInfo.info.thresholdIndex_yen
  264. );
  265. $(document).trigger('opacityBordersChanged', { minGray: minGray, maxGray: textureInfo.info.thresholdIndex_yen});
  266. });
  267. }
  268. }
  269. function initTextures(imgInfo, imageParams, whileInit) {
  270. // set initial array to index
  271. if(textures[imageParams.textureIndex] == undefined
  272. || textures[imageParams.textureIndex] == null) {
  273. textures[imageParams.textureIndex] = [];
  274. }
  275. // using texture
  276. texture = initTexture(imageParams.texture);
  277. textures[imageParams.textureIndex].push(texture);
  278. // fetch new sprites of same time frame
  279. if(imageParams.spriteIndex < imgInfo.numberOfSprites - 1) {
  280. nextSpriteIndex = imageParams.spriteIndex + 1;
  281. nextSpriteId = textureInfo.sprites[imageParams.textureIndex][nextSpriteIndex].$oid
  282. helper.downloadImage(spriteUrl + nextSpriteId, imageParams.textureIndex, nextSpriteIndex, whileInit);
  283. return;
  284. }
  285. // inform the rest, that the first frame is loaded completely
  286. if(whileInit && imageParams.textureIndex == 0) {
  287. $(document).trigger('firstFrameSpritesCompleted');
  288. }
  289. // todo some logic
  290. if(!imgInfo.multipleFrames) {
  291. currentTexture = 0;
  292. return;
  293. } else {
  294. var numberOfFrames = Object.keys(textureInfo.sprites).length,
  295. nextIndex = null,
  296. nextFrameName = null,
  297. nextFramePath = null;
  298. framesDownloaded++;
  299. if(framesDownloaded == 1) {
  300. currentTexture = 0;
  301. }
  302. currentMaxFrame = imgInfo.frameFrom + framesDownloaded - 1;
  303. if(framesDownloaded > 1) {
  304. // updating frame control maximums
  305. updateFrameControlsMaxFrame();
  306. }
  307. if(numberOfFrames == framesDownloaded) {
  308. return;
  309. } else {
  310. nextIndex = framesDownloaded;
  311. nextFrameName = textureInfo.sprites[nextIndex][0].$oid;
  312. var framePath = spriteUrl + nextFrameName;
  313. helper.downloadImage(framePath, nextIndex, false);
  314. }
  315. }
  316. }
  317. function initTexture(texture) {
  318. texture.magFilter = THREE.LinearFilter;
  319. texture.minFilter = THREE.LinearFilter;
  320. texture.needsUpdate = true;
  321. return texture;
  322. }
  323. function getCurrentTexture() {
  324. return textures[currentTexture];
  325. }
  326. function useFrameControls() {
  327. return (imgInfo.multipleFrames && (imgInfo.frameTo - imgInfo.frameFrom) != 0);
  328. }
  329. function initFrameControls() {
  330. if(!useFrameControls()) {
  331. return;
  332. }
  333. $('#frame-controls').removeClass('hidden');
  334. var $frameSlider = $('#frame-slider'),
  335. $playButton = $('#frame-play'),
  336. $pauseButton = $('#frame-pause'),
  337. $currentFrameInput = $('#currentFrame'),
  338. playId = $playButton.attr('id'),
  339. pauseId = $pauseButton.attr('id'),
  340. minFrame = imgInfo.frameFrom;
  341. $currentFrameInput.val(minFrame);
  342. var play = function() {
  343. if(Object.keys(textures).length == 1) {
  344. console.warn('only one texture loaded, can not play yet');
  345. return;
  346. }
  347. $playButton.addClass('hidden');
  348. $pauseButton.removeClass('hidden');
  349. playFrames = true;
  350. $frameSlider.slider({disabled: true});
  351. $currentFrameInput.prop('disabled', true);
  352. }
  353. var pause = function() {
  354. $playButton.removeClass('hidden');
  355. $pauseButton.addClass('hidden');
  356. playFrames = false;
  357. $frameSlider.slider({disabled: false});
  358. $currentFrameInput.prop('disabled', false);
  359. }
  360. $('.frame-button').click(function() {
  361. var $this = $(this),
  362. thisId = $this.attr('id');
  363. if(thisId == playId) {
  364. play();
  365. } else if(thisId == pauseId) {
  366. pause();
  367. }
  368. });
  369. $(document).on('zoomActionFinished', function(e, params) {
  370. zoomedIn = params.zoomAction == 'zoomIn';
  371. if(zoomedIn) {
  372. pause();
  373. currentTexture = minFrame + params.textureNumber;
  374. updateFrameControls();
  375. $frameSlider.slider({disabled: true});
  376. $currentFrameInput.prop('disabled', true);
  377. $playButton.prop('disabled', true);
  378. $pauseButton.prop('disabled', true);
  379. } else {
  380. $frameSlider.slider({disabled: false});
  381. $currentFrameInput.prop('disabled', false);
  382. $playButton.prop('disabled', false);
  383. $pauseButton.prop('disabled', false);
  384. }
  385. });
  386. $frameSlider.slider(
  387. {
  388. min: minFrame,
  389. max: currentMaxFrame,
  390. slide: function( event, ui ) {
  391. currentTexture = ui.value - minFrame;
  392. updateTexture();
  393. $currentFrameInput.val(ui.value);
  394. }
  395. }
  396. );
  397. $currentFrameInput.change(function() {
  398. var value = parseInt($(this).val());
  399. if(value >= imgInfo.frameFrom && currentMaxFrame >= value) {
  400. currentTexture = value - minFrame;
  401. updateTexture();
  402. $frameSlider.slider('value', value);
  403. } else {
  404. $(this).val($frameSlider.slider('value'));
  405. }
  406. });
  407. }
  408. function updateFrameControlsMaxFrame() {
  409. if(!useFrameControls()) {
  410. return;
  411. }
  412. var $frameSlider = $('#frame-slider');
  413. $frameSlider.slider('option', 'max', currentMaxFrame);
  414. }
  415. function updateFrameControls() {
  416. if(!useFrameControls()) {
  417. return;
  418. }
  419. var $frameSlider = $('#frame-slider'),
  420. $currentFrameInput = $('#currentFrame'),
  421. minFrame = imgInfo.frameFrom,
  422. value = currentTexture + minFrame;
  423. $frameSlider.slider('value', value);
  424. $currentFrameInput.val(value);
  425. }
  426. function init() {
  427. rendererSizeHolder = calculateWidthHeight();
  428. width = rendererSizeHolder.width.px;
  429. height = rendererSizeHolder.height.px;
  430. //width = window.innerWidth;
  431. //height = window.innerHeight;
  432. camera = new THREE.PerspectiveCamera( 45, width / height, .1, 1000 );
  433. camera.position.z = 2;
  434. cameraRTT = new THREE.PerspectiveCamera( 45, width / height, .1, 1000 );
  435. cameraRTT.position.z = 2;
  436. scene = new THREE.Scene();
  437. sceneRTT = new THREE.Scene();
  438. rtTexture = new THREE.WebGLRenderTarget( width, height, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat } );
  439. var geometry = geometryHelper.createBoxGeometry(originalDimension, currentVolumeDimension);
  440. var attributes = {
  441. frontColor: {type: 'c', value: [] }
  442. }
  443. material = new THREE.ShaderMaterial({
  444. attributes: attributes,
  445. vertexShader: vertexShader,
  446. fragmentShader: fragmentSimleShader,
  447. side: THREE.FrontSide
  448. });
  449. var spriteMaps = getCurrentTexture();
  450. var transferImageData = transferHelper.getCurrentTransferFunction();
  451. var transferTexture = new THREE.Texture(transferImageData);
  452. transferTexture.needsUpdate = true;
  453. var uniforms = {
  454. tBackground: {type: 't', value: rtTexture},
  455. tvSlices: {type: 'tv', value: spriteMaps},
  456. tTransfer: { type: 't', value: transferTexture},
  457. steps: {type: 'f', value: 100},
  458. numberOfSlices: {type: 'f', value: imgInfo.numberOfSlices },
  459. numberOfSprites: {type: 'f', value: imgInfo.numberOfSprites },
  460. slicesPerSprite: {type: 'f', value: imgInfo.slicesPerSprite },
  461. slicesOverX: {type: 'f', value: imgInfo.slicesOverX },
  462. slicesOverY: {type: 'f', value: imgInfo.slicesOverY },
  463. };
  464. materialScreen = new THREE.ShaderMaterial({
  465. attributes: attributes,
  466. uniforms: uniforms,
  467. vertexShader: vertexShader,
  468. fragmentShader: fragmentShader,
  469. side: THREE.BackSide,
  470. transparent: true
  471. });
  472. backgroundBox = new THREE.Mesh(geometry, material);
  473. sceneRTT.add(backgroundBox);
  474. frontBox = new THREE.Mesh(geometry, materialScreen);//
  475. scene.add(frontBox);
  476. objectsToIntersect.push(frontBox);
  477. translateBoxes(-0.5, -0.5, -0.5 * currentVolumeDimension.getZStretchFactor());
  478. rotateBoxesX(Math.PI / -2);
  479. //rotateBoxesY(Math.PI);
  480. //rotateBoxesZ(Math.PI);
  481. renderer = new THREE.WebGLRenderer();
  482. renderer.setSize(width, height);
  483. renderer.domElement.style.width = rendererSizeHolder.width.percent + '%';
  484. renderer.domElement.style.height = rendererSizeHolder.height.percent + '%';
  485. renderer.setClearColor(0xffffff, 1);
  486. container.appendChild(renderer.domElement);
  487. $canvas = $('canvas', $container);
  488. controls1 = new THREE.OrbitControls( camera, renderer.domElement );
  489. controls1.damping = 0.2;
  490. controls2 = new THREE.OrbitControls( cameraRTT, renderer.domElement );
  491. controls2.damping = 0.2;
  492. rendererContext = renderer.context;
  493. raycaster = new THREE.Raycaster();
  494. $(document).trigger('initFinished');
  495. }
  496. function rotateBoxesX(radian) {
  497. rotationMatrix = new THREE.Matrix4().makeRotationX(radian);
  498. rotateBoxes(rotationMatrix);
  499. }
  500. function rotateBoxesY(radian) {
  501. rotationMatrix = new THREE.Matrix4().makeRotationY(radian);
  502. rotateBoxes(rotationMatrix);
  503. }
  504. function rotateBoxesZ(radian) {
  505. rotationMatrix = new THREE.Matrix4().makeRotationZ(radian);
  506. rotateBoxes(rotationMatrix);
  507. }
  508. function rotateBoxes(matrix) {
  509. backgroundBox.applyMatrix(rotationMatrix);
  510. frontBox.applyMatrix(rotationMatrix);
  511. }
  512. function translateBoxes(x, y, z) {
  513. translationMatrix = new THREE.Matrix4().makeTranslation(x, y, z);
  514. backgroundBox.applyMatrix(translationMatrix);
  515. frontBox.applyMatrix(translationMatrix);
  516. }
  517. function initSliders() {
  518. initLayerSliders();
  519. // init gray value slider
  520. GenericSlider.initSlider(
  521. slider = $( "#gray-slider" ),
  522. sliderInputs = $('input.gray'),
  523. minGray,
  524. maxGray,
  525. minGray,
  526. maxGray,
  527. function(values) {
  528. $(document).trigger(
  529. 'opacityBordersChanged',
  530. {
  531. minGray: values[0],
  532. maxGray : values[1]
  533. }
  534. );
  535. }
  536. );
  537. $('#gray-slider-container').on('controlsShowed', function() {
  538. var values = $("#gray-slider").slider('values');
  539. $(document).trigger('opacityBordersChanged', { minGray: values[0], maxGray: values[1] });
  540. });
  541. GenericSlider.initSimpleSlider(
  542. slider = $('#background-slider'),
  543. sliderInput = $('#background-input'),
  544. startVal = 255,
  545. 0,
  546. 255,
  547. function(value) {
  548. var colorFloat = calculateGrayFloat(value);
  549. renderer.setClearColor(
  550. new THREE.Color(colorFloat, colorFloat, colorFloat),
  551. 1
  552. );
  553. }
  554. );
  555. }
  556. function initLayerSliders() {
  557. // init xlayer slider
  558. GenericSlider.initSlider(
  559. $( "#xlayer-slider" ),
  560. sliderInputs = $('input.xlayer'),
  561. currentVolumeDimension.xmin,
  562. currentVolumeDimension.xmax,
  563. currentVolumeDimension.xmin,
  564. currentVolumeDimension.xmax,
  565. function(values) {
  566. dimMin = currentVolumeDimension.xmin;
  567. dimMax = currentVolumeDimension.xmax;
  568. currentDimension.xmin = calculateLayerFloat(values[0], dimMin, dimMax);
  569. currentDimension.xmax = calculateLayerFloat(values[1], dimMin, dimMax);
  570. updateCubeLayers(currentDimension);
  571. },
  572. function() {
  573. values = Array(2);
  574. values[0] = calculateLayerInt(currentDimension.xmin, currentVolumeDimension.xmin, currentVolumeDimension.xmax );
  575. values[1] = calculateLayerInt(currentDimension.xmax, currentVolumeDimension.xmin, currentVolumeDimension.xmax );
  576. return values;
  577. }
  578. );
  579. // init ylayer slider
  580. GenericSlider.initSlider(
  581. $( "#ylayer-slider" ),
  582. sliderInputs = $('input.ylayer'),
  583. currentVolumeDimension.ymin,
  584. currentVolumeDimension.ymax,
  585. currentVolumeDimension.ymin,
  586. currentVolumeDimension.ymax,
  587. function(values) {
  588. dimMin = currentVolumeDimension.ymin;
  589. dimMax = currentVolumeDimension.ymax;
  590. currentDimension.ymin = calculateLayerFloat(values[0], dimMin, dimMax);
  591. currentDimension.ymax = calculateLayerFloat(values[1], dimMin, dimMax);
  592. updateCubeLayers(currentDimension);
  593. },
  594. function() {
  595. values = Array(2);
  596. values[0] = calculateLayerInt(currentDimension.ymin, currentVolumeDimension.ymin, currentVolumeDimension.ymax );
  597. values[1] = calculateLayerInt(currentDimension.ymax, currentVolumeDimension.ymin, currentVolumeDimension.ymax );
  598. return values;
  599. }
  600. );
  601. // init zlayer slider
  602. GenericSlider.initSlider(
  603. $( "#zlayer-slider" ),
  604. sliderInputs = $('input.zlayer'),
  605. currentVolumeDimension.zmin,
  606. currentVolumeDimension.zmax,
  607. currentVolumeDimension.zmin,
  608. currentVolumeDimension.zmax,
  609. function(values) {
  610. dimMin = currentVolumeDimension.zmin;
  611. dimMax = currentVolumeDimension.zmax;
  612. currentDimension.zmin = calculateLayerFloat(values[0], dimMin, dimMax),
  613. currentDimension.zmax = calculateLayerFloat(values[1], dimMin, dimMax);
  614. updateCubeLayers(currentDimension);
  615. },
  616. function() {
  617. values = Array(2);
  618. values[0] = calculateLayerInt(currentDimension.zmin, currentVolumeDimension.zmin, currentVolumeDimension.zmax );
  619. values[1] = calculateLayerInt(currentDimension.zmax, currentVolumeDimension.zmin, currentVolumeDimension.zmax );
  620. return values;
  621. }
  622. );
  623. }
  624. function repositionLayerSliders() {
  625. initLayerSliders();
  626. $.each($('.slider.layer'), function(index, value) {
  627. $(value).trigger('reposition');
  628. });
  629. updateCubeLayers(currentDimension);
  630. }
  631. var prevTime = Date.now();
  632. var fps = 0;
  633. var frames = 0;
  634. function animate() {
  635. requestAnimationFrame( animate );
  636. $container.trigger('animation');
  637. var numberOfTextures = Object.keys(textures).length;
  638. var now = Date.now();
  639. frames++;
  640. if(now > prevTime + 1000) {
  641. fps = (frames * 1000) / (now - prevTime);
  642. if(adjustSteps) {
  643. if(fps < 10) {
  644. stepHelper.decreaseSteps();
  645. } else if(fps > 15) {
  646. stepHelper.increaseSteps();
  647. }
  648. }
  649. prevTime = now;
  650. frames = 0;
  651. }
  652. if(playFrames && numberOfTextures > 1) {
  653. var timeStamp = (new Date()).getTime();
  654. if(timeStamp - textureTimestamp > 400) {
  655. currentTexture++;
  656. if(currentTexture >= numberOfTextures) {
  657. currentTexture = 0;
  658. }
  659. updateTexture();
  660. textureTimestamp = timeStamp;
  661. updateFrameControls();
  662. }
  663. }
  664. if(nextCubeDeletionTimeStamp == null && intersectCubesTimeStamps.length != 0) {
  665. nextCubeDeletionTimeStamp = intersectCubesTimeStamps.shift();
  666. }
  667. if((Date.now() - nextCubeDeletionTimeStamp) > 1500) {
  668. cubeToDelete = intersectCubes.shift();
  669. scene.remove(cubeToDelete);
  670. nextCubeDeletionTimeStamp = null;
  671. }
  672. if(transferHelper.transferFunctionChanged()) {
  673. var transfer = new THREE.Texture(transferHelper.getCurrentTransferFunction());
  674. transfer.needsUpdate = true;
  675. materialScreen.uniforms.tTransfer.value = transfer;
  676. }
  677. cameraPoint = camera.position.clone();
  678. overviewHelper.updateCameraPosition(cameraPoint);
  679. statsHelper.update();
  680. controls1.update();
  681. controls2.update();
  682. render();
  683. if(saveImage) {
  684. $('#save-canvas').trigger('click', { source: 'animate-function', imageUrl: renderer.domElement.toDataURL() });
  685. saveImage = false;
  686. }
  687. }
  688. function updateTexture(textures) {
  689. if(textures == undefined || textures == null) {
  690. textures = getCurrentTexture();
  691. }
  692. $.each(textures, function(index, texture) {
  693. value.needsUpdate = true;
  694. });
  695. materialScreen.uniforms.tvSlices.value = textures;
  696. }
  697. function render() {
  698. renderer.clear();
  699. renderer.context.clearDepth(-50.0);
  700. renderer.context.depthFunc(renderer.context.GEQUAL);
  701. renderer.render(sceneRTT, cameraRTT, rtTexture, true);
  702. renderer.context.clearDepth(50.0);
  703. renderer.context.depthFunc(renderer.context.LEQUAL);
  704. renderer.render(scene, camera);
  705. overviewHelper.render();
  706. }
  707. function updateCubeLayers(geometryDimension) {
  708. var geometry = geometryHelper.createBoxGeometry(geometryDimension, currentVolumeDimension);
  709. var colorArray = geometry.attributes.frontColor.array,
  710. positionArray = geometry.attributes.position.array;
  711. frontBox.geometry.attributes.frontColor.array = colorArray;
  712. frontBox.geometry.attributes.frontColor.needsUpdate = true;
  713. frontBox.geometry.attributes.position.array = positionArray;
  714. frontBox.geometry.attributes.position.needsUpdate = true;
  715. }
  716. // invert function of calculateLayerFloat
  717. function calculateLayerInt(position, dimMin, dimMax) {
  718. if(position <= 0.005) {
  719. return dimMin;
  720. }
  721. if(position >= 0.995) {
  722. return dimMax;
  723. }
  724. value = Math.round(position * (dimMax - dimMin) + dimMin);
  725. return value;
  726. }
  727. // calculate the float value for a layer input integer
  728. // 150 of [0, 299] will be 0.5
  729. function calculateLayerFloat(value, dimMin, dimMax) {
  730. var floatVal = (value - dimMin) / (dimMax - dimMin);
  731. if (floatVal == 0) {
  732. return 0.005;
  733. }
  734. if (floatVal == 1) {
  735. return 0.995;
  736. }
  737. return floatVal;
  738. }
  739. function calculateGrayFloat(value) {
  740. return value / 255.0;
  741. }
  742. function distance (v1, v2) {
  743. dx = v1.x - v2.x;
  744. dy = v1.y - v2.y;
  745. dz = v1.z - v2.z;
  746. return Math.sqrt(dx*dx+dy*dy+dz*dz);
  747. }
  748. function calculateWidthHeight() {
  749. downScaleFactor = 0.66;
  750. valueholder = {
  751. height: {},
  752. width: {}
  753. }
  754. containerHeight = $container.height();
  755. volumeInfoHeight = $('#volume-information').height();
  756. headerHeight = $('header').height();
  757. valueholder.height.px = (containerHeight - volumeInfoHeight) * downScaleFactor;
  758. volumeInfoHeightPercent = Math.floor(volumeInfoHeight / containerHeight * 100);
  759. valueholder.height.percent = 100 - volumeInfoHeightPercent;
  760. valueholder.width.px = $container.width() * downScaleFactor;
  761. valueholder.width.percent = 100;
  762. return valueholder;
  763. }
  764. function hideBottomControlsContainer() {
  765. var bottomControlsContainer = $('div#bottom-controls-container'),
  766. bottomControls = $('div#bottom-controls'),
  767. filledById = bottomControls.attr('filledBy'),
  768. filledBy = $('#' + filledById);
  769. // writing data back to original, because append MOVES the children
  770. if(filledBy.length == 1) {
  771. filledBy = $(filledBy[0]);
  772. filledByControlHolder = filledBy.children('.control-holder')[0];
  773. $(filledByControlHolder).append(bottomControls.children());
  774. }
  775. bottomControls.attr('filledBy', '');
  776. bottomControlsContainer.addClass('hidden');
  777. return filledById;
  778. }
  779. function addResolutionLinks() {
  780. $resSpan.text(config.defaultSize);
  781. textureSizes = config.textureSizes;
  782. textureSizes.forEach(function(size) {
  783. if(size > maximumTextureSize) {
  784. return;
  785. }
  786. href = size == config.defaultSize ? '' : 'href="#"';
  787. $resolutionLinks.append('<a '+href+' class="res-link" data="'+size+'">'+size+'</a> ');
  788. });
  789. }