Application.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  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. }
  224. }
  225. function initTextures(imgInfo, imageParams, whileInit) {
  226. // set initial array to index
  227. if(textures[imageParams.textureIndex] == undefined
  228. || textures[imageParams.textureIndex] == null) {
  229. textures[imageParams.textureIndex] = [];
  230. }
  231. // using texture
  232. texture = initTexture(imageParams.texture);
  233. textures[imageParams.textureIndex].push(texture);
  234. // fetch new sprites of same time frame
  235. if(imageParams.spriteIndex < imgInfo.numberOfSprites - 1) {
  236. nextSpriteIndex = imageParams.spriteIndex + 1;
  237. nextSpriteId = textureInfo.sprites[imageParams.textureIndex][nextSpriteIndex].$oid
  238. helper.downloadImage(spriteUrl + nextSpriteId, imageParams.textureIndex, nextSpriteIndex, whileInit);
  239. return;
  240. }
  241. // inform the rest, that the first frame is loaded completely
  242. if(whileInit && imageParams.textureIndex == 0) {
  243. $(document).trigger('firstFrameSpritesCompleted');
  244. }
  245. // todo some logic
  246. if(!imgInfo.multipleFrames) {
  247. currentTexture = 0;
  248. return;
  249. } else {
  250. var numberOfFrames = Object.keys(textureInfo.sprites).length,
  251. nextIndex = null,
  252. nextFrameName = null,
  253. nextFramePath = null;
  254. framesDownloaded++;
  255. if(framesDownloaded == 1) {
  256. currentTexture = 0;
  257. }
  258. currentMaxFrame = imgInfo.frameFrom + framesDownloaded - 1;
  259. if(framesDownloaded > 1) {
  260. // updating frame control maximums
  261. updateFrameControlsMaxFrame();
  262. }
  263. if(numberOfFrames == framesDownloaded) {
  264. return;
  265. } else {
  266. nextIndex = framesDownloaded;
  267. nextFrameName = textureInfo.sprites[nextIndex][0].$oid;
  268. var framePath = spriteUrl + nextFrameName;
  269. helper.downloadImage(framePath, nextIndex, false);
  270. }
  271. }
  272. }
  273. function initTexture(texture) {
  274. texture.magFilter = THREE.LinearFilter;
  275. texture.minFilter = THREE.LinearFilter;
  276. texture.needsUpdate = true;
  277. return texture;
  278. }
  279. function getCurrentTexture() {
  280. return textures[currentTexture];
  281. }
  282. function useFrameControls() {
  283. return (imgInfo.multipleFrames && (imgInfo.frameTo - imgInfo.frameFrom) != 0);
  284. }
  285. function initFrameControls() {
  286. if(!useFrameControls()) {
  287. return;
  288. }
  289. $('#frame-controls').removeClass('hidden');
  290. var $frameSlider = $('#frame-slider'),
  291. $playButton = $('#frame-play'),
  292. $pauseButton = $('#frame-pause'),
  293. $currentFrameInput = $('#currentFrame'),
  294. playId = $playButton.attr('id'),
  295. pauseId = $pauseButton.attr('id'),
  296. minFrame = imgInfo.frameFrom;
  297. $currentFrameInput.val(minFrame);
  298. var play = function() {
  299. if(Object.keys(textures).length == 1) {
  300. console.warn('only one texture loaded, can not play yet');
  301. return;
  302. }
  303. $playButton.addClass('hidden');
  304. $pauseButton.removeClass('hidden');
  305. playFrames = true;
  306. $frameSlider.slider({disabled: true});
  307. $currentFrameInput.prop('disabled', true);
  308. }
  309. var pause = function() {
  310. $playButton.removeClass('hidden');
  311. $pauseButton.addClass('hidden');
  312. playFrames = false;
  313. $frameSlider.slider({disabled: false});
  314. $currentFrameInput.prop('disabled', false);
  315. }
  316. $('.frame-button').click(function() {
  317. var $this = $(this),
  318. thisId = $this.attr('id');
  319. if(thisId == playId) {
  320. play();
  321. } else if(thisId == pauseId) {
  322. pause();
  323. }
  324. });
  325. $(document).on('zoomActionFinished', function(e, params) {
  326. zoomedIn = params.zoomAction == 'zoomIn';
  327. if(zoomedIn) {
  328. pause();
  329. currentTexture = minFrame + params.textureNumber;
  330. updateFrameControls();
  331. $frameSlider.slider({disabled: true});
  332. $currentFrameInput.prop('disabled', true);
  333. $playButton.prop('disabled', true);
  334. $pauseButton.prop('disabled', true);
  335. } else {
  336. $frameSlider.slider({disabled: false});
  337. $currentFrameInput.prop('disabled', false);
  338. $playButton.prop('disabled', false);
  339. $pauseButton.prop('disabled', false);
  340. }
  341. });
  342. $frameSlider.slider(
  343. {
  344. min: minFrame,
  345. max: currentMaxFrame,
  346. slide: function( event, ui ) {
  347. currentTexture = ui.value - minFrame;
  348. updateTexture();
  349. $currentFrameInput.val(ui.value);
  350. }
  351. }
  352. );
  353. $currentFrameInput.change(function() {
  354. var value = parseInt($(this).val());
  355. if(value >= imgInfo.frameFrom && currentMaxFrame >= value) {
  356. currentTexture = value - minFrame;
  357. updateTexture();
  358. $frameSlider.slider('value', value);
  359. } else {
  360. $(this).val($frameSlider.slider('value'));
  361. }
  362. });
  363. }
  364. function updateFrameControlsMaxFrame() {
  365. if(!useFrameControls()) {
  366. return;
  367. }
  368. var $frameSlider = $('#frame-slider');
  369. $frameSlider.slider('option', 'max', currentMaxFrame);
  370. }
  371. function updateFrameControls() {
  372. if(!useFrameControls()) {
  373. return;
  374. }
  375. var $frameSlider = $('#frame-slider'),
  376. $currentFrameInput = $('#currentFrame'),
  377. minFrame = imgInfo.frameFrom,
  378. value = currentTexture + minFrame;
  379. $frameSlider.slider('value', value);
  380. $currentFrameInput.val(value);
  381. }
  382. function init() {
  383. rendererSizeHolder = calculateWidthHeight();
  384. width = rendererSizeHolder.width.px;
  385. height = rendererSizeHolder.height.px;
  386. //width = window.innerWidth;
  387. //height = window.innerHeight;
  388. camera = new THREE.PerspectiveCamera( 45, width / height, .1, 1000 );
  389. camera.position.z = 2;
  390. cameraRTT = new THREE.PerspectiveCamera( 45, width / height, .1, 1000 );
  391. cameraRTT.position.z = 2;
  392. scene = new THREE.Scene();
  393. sceneRTT = new THREE.Scene();
  394. rtTexture = new THREE.WebGLRenderTarget( width, height, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat } );
  395. var geometry = geometryHelper.createBoxGeometry(originalDimension, currentVolumeDimension);
  396. var attributes = {
  397. frontColor: {type: 'c', value: [] }
  398. }
  399. material = new THREE.ShaderMaterial({
  400. attributes: attributes,
  401. vertexShader: vertexShader,
  402. fragmentShader: fragmentSimleShader,
  403. side: THREE.FrontSide
  404. });
  405. var spriteMaps = getCurrentTexture();
  406. var transferImageData = transferHelper.getCurrentTransferFunction();
  407. var transferTexture = new THREE.Texture(transferImageData);
  408. transferTexture.needsUpdate = true;
  409. var uniforms = {
  410. tBackground: {type: 't', value: rtTexture},
  411. tvSlices: {type: 'tv', value: spriteMaps},
  412. tTransfer: { type: 't', value: transferTexture},
  413. steps: {type: 'f', value: 100},
  414. numberOfSlices: {type: 'f', value: imgInfo.numberOfSlices },
  415. numberOfSprites: {type: 'f', value: imgInfo.numberOfSprites },
  416. slicesPerSprite: {type: 'f', value: imgInfo.slicesPerSprite },
  417. slicesOverX: {type: 'f', value: imgInfo.slicesOverX },
  418. slicesOverY: {type: 'f', value: imgInfo.slicesOverY },
  419. };
  420. materialScreen = new THREE.ShaderMaterial({
  421. attributes: attributes,
  422. uniforms: uniforms,
  423. vertexShader: vertexShader,
  424. fragmentShader: fragmentShader,
  425. side: THREE.BackSide,
  426. transparent: true
  427. });
  428. backgroundBox = new THREE.Mesh(geometry, material);
  429. sceneRTT.add(backgroundBox);
  430. frontBox = new THREE.Mesh(geometry, materialScreen);//
  431. scene.add(frontBox);
  432. objectsToIntersect.push(frontBox);
  433. translateBoxes(-0.5, -0.5, -0.5);
  434. rotateBoxesX(Math.PI / -2);
  435. //rotateBoxesY(Math.PI);
  436. //rotateBoxesZ(Math.PI);
  437. renderer = new THREE.WebGLRenderer();
  438. renderer.setSize(width, height);
  439. renderer.domElement.style.width = rendererSizeHolder.width.percent + '%';
  440. renderer.domElement.style.height = rendererSizeHolder.height.percent + '%';
  441. renderer.setClearColor(0xffffff, 1);
  442. container.appendChild(renderer.domElement);
  443. $canvas = $('canvas', $container);
  444. controls1 = new THREE.OrbitControls( camera, renderer.domElement );
  445. controls1.damping = 0.2;
  446. controls2 = new THREE.OrbitControls( cameraRTT, renderer.domElement );
  447. controls2.damping = 0.2;
  448. rendererContext = renderer.context;
  449. raycaster = new THREE.Raycaster();
  450. }
  451. function rotateBoxesX(radian) {
  452. rotationMatrix = new THREE.Matrix4().makeRotationX(radian);
  453. rotateBoxes(rotationMatrix);
  454. }
  455. function rotateBoxesY(radian) {
  456. rotationMatrix = new THREE.Matrix4().makeRotationY(radian);
  457. rotateBoxes(rotationMatrix);
  458. }
  459. function rotateBoxesZ(radian) {
  460. rotationMatrix = new THREE.Matrix4().makeRotationZ(radian);
  461. rotateBoxes(rotationMatrix);
  462. }
  463. function rotateBoxes(matrix) {
  464. backgroundBox.applyMatrix(rotationMatrix);
  465. frontBox.applyMatrix(rotationMatrix);
  466. }
  467. function translateBoxes(x, y, z) {
  468. translationMatrix = new THREE.Matrix4().makeTranslation(x, y, z);
  469. backgroundBox.applyMatrix(translationMatrix);
  470. frontBox.applyMatrix(translationMatrix);
  471. }
  472. function initSliders() {
  473. initLayerSliders();
  474. // init gray value slider
  475. GenericSlider.initSlider(
  476. slider = $( "#gray-slider" ),
  477. sliderInputs = $('input.gray'),
  478. minGray,
  479. maxGray,
  480. function(values) {
  481. $(document).trigger(
  482. 'opacityBordersChanged',
  483. {
  484. minGray: values[0],
  485. maxGray : values[1]
  486. }
  487. );
  488. }
  489. );
  490. $('#gray-slider-container').on('controlsShowed', function() {
  491. var values = $("#gray-slider").slider('values');
  492. $(document).trigger('opacityBordersChanged', { minGray: values[0], maxGray: values[1] });
  493. });
  494. GenericSlider.initSimpleSlider(
  495. slider = $('#background-slider'),
  496. sliderInput = $('#background-input'),
  497. startVal = 255,
  498. 0,
  499. 255,
  500. function(value) {
  501. var colorFloat = calculateGrayFloat(value);
  502. renderer.setClearColor(
  503. new THREE.Color(colorFloat, colorFloat, colorFloat),
  504. 1
  505. );
  506. }
  507. );
  508. }
  509. function initLayerSliders() {
  510. // init xlayer slider
  511. GenericSlider.initSlider(
  512. $( "#xlayer-slider" ),
  513. sliderInputs = $('input.xlayer'),
  514. currentVolumeDimension.xmin,
  515. currentVolumeDimension.xmax,
  516. function(values) {
  517. dimMin = currentVolumeDimension.xmin;
  518. dimMax = currentVolumeDimension.xmax;
  519. currentDimension.xmin = calculateLayerFloat(values[0], dimMin, dimMax);
  520. currentDimension.xmax = calculateLayerFloat(values[1], dimMin, dimMax);
  521. updateCubeLayers(currentDimension);
  522. },
  523. function() {
  524. values = Array(2);
  525. values[0] = calculateLayerInt(currentDimension.xmin, currentVolumeDimension.xmin, currentVolumeDimension.xmax );
  526. values[1] = calculateLayerInt(currentDimension.xmax, currentVolumeDimension.xmin, currentVolumeDimension.xmax );
  527. return values;
  528. }
  529. );
  530. // init ylayer slider
  531. GenericSlider.initSlider(
  532. $( "#ylayer-slider" ),
  533. sliderInputs = $('input.ylayer'),
  534. currentVolumeDimension.ymin,
  535. currentVolumeDimension.ymax,
  536. function(values) {
  537. dimMin = currentVolumeDimension.ymin;
  538. dimMax = currentVolumeDimension.ymax;
  539. currentDimension.ymin = calculateLayerFloat(values[0], dimMin, dimMax);
  540. currentDimension.ymax = calculateLayerFloat(values[1], dimMin, dimMax);
  541. updateCubeLayers(currentDimension);
  542. },
  543. function() {
  544. values = Array(2);
  545. values[0] = calculateLayerInt(currentDimension.ymin, currentVolumeDimension.ymin, currentVolumeDimension.ymax );
  546. values[1] = calculateLayerInt(currentDimension.ymax, currentVolumeDimension.ymin, currentVolumeDimension.ymax );
  547. return values;
  548. }
  549. );
  550. // init zlayer slider
  551. GenericSlider.initSlider(
  552. $( "#zlayer-slider" ),
  553. sliderInputs = $('input.zlayer'),
  554. currentVolumeDimension.zmin,
  555. currentVolumeDimension.zmax,
  556. function(values) {
  557. dimMin = currentVolumeDimension.zmin;
  558. dimMax = currentVolumeDimension.zmax;
  559. currentDimension.zmin = calculateLayerFloat(values[0], dimMin, dimMax),
  560. currentDimension.zmax = calculateLayerFloat(values[1], dimMin, dimMax);
  561. updateCubeLayers(currentDimension);
  562. },
  563. function() {
  564. values = Array(2);
  565. values[0] = calculateLayerInt(currentDimension.zmin, currentVolumeDimension.zmin, currentVolumeDimension.zmax );
  566. values[1] = calculateLayerInt(currentDimension.zmax, currentVolumeDimension.zmin, currentVolumeDimension.zmax );
  567. return values;
  568. }
  569. );
  570. }
  571. function repositionLayerSliders() {
  572. initLayerSliders();
  573. $.each($('.slider.layer'), function(index, value) {
  574. $(value).trigger('reposition');
  575. });
  576. updateCubeLayers(currentDimension);
  577. }
  578. var prevTime = Date.now();
  579. var fps = 0;
  580. var frames = 0;
  581. function animate() {
  582. requestAnimationFrame( animate );
  583. $container.trigger('animation');
  584. var numberOfTextures = Object.keys(textures).length;
  585. var now = Date.now();
  586. frames++;
  587. if(now > prevTime + 1000) {
  588. fps = (frames * 1000) / (now - prevTime);
  589. if(adjustSteps) {
  590. if(fps < 10) {
  591. stepHelper.decreaseSteps();
  592. } else if(fps > 15) {
  593. stepHelper.increaseSteps();
  594. }
  595. }
  596. prevTime = now;
  597. frames = 0;
  598. }
  599. if(playFrames && numberOfTextures > 1) {
  600. var timeStamp = (new Date()).getTime();
  601. if(timeStamp - textureTimestamp > 400) {
  602. currentTexture++;
  603. if(currentTexture >= numberOfTextures) {
  604. currentTexture = 0;
  605. }
  606. updateTexture();
  607. textureTimestamp = timeStamp;
  608. updateFrameControls();
  609. }
  610. }
  611. if(nextCubeDeletionTimeStamp == null && intersectCubesTimeStamps.length != 0) {
  612. nextCubeDeletionTimeStamp = intersectCubesTimeStamps.shift();
  613. }
  614. if((Date.now() - nextCubeDeletionTimeStamp) > 1500) {
  615. cubeToDelete = intersectCubes.shift();
  616. scene.remove(cubeToDelete);
  617. nextCubeDeletionTimeStamp = null;
  618. }
  619. if(transferHelper.transferFunctionChanged()) {
  620. var transfer = new THREE.Texture(transferHelper.getCurrentTransferFunction());
  621. transfer.needsUpdate = true;
  622. materialScreen.uniforms.tTransfer.value = transfer;
  623. }
  624. cameraPoint = camera.position.clone();
  625. overviewHelper.updateCameraPosition(cameraPoint);
  626. statsHelper.update();
  627. controls1.update();
  628. controls2.update();
  629. render();
  630. if(saveImage) {
  631. $('#save-canvas').trigger('click', { source: 'animate-function', imageUrl: renderer.domElement.toDataURL() });
  632. saveImage = false;
  633. }
  634. }
  635. function updateTexture(textures) {
  636. if(textures == undefined || textures == null) {
  637. textures = getCurrentTexture();
  638. }
  639. $.each(textures, function(index, texture) {
  640. value.needsUpdate = true;
  641. });
  642. materialScreen.uniforms.tvSlices.value = textures;
  643. }
  644. function render() {
  645. renderer.clear();
  646. renderer.context.clearDepth(-50.0);
  647. renderer.context.depthFunc(renderer.context.GEQUAL);
  648. renderer.render(sceneRTT, cameraRTT, rtTexture, true);
  649. renderer.context.clearDepth(50.0);
  650. renderer.context.depthFunc(renderer.context.LEQUAL);
  651. renderer.render(scene, camera);
  652. overviewHelper.render();
  653. }
  654. function updateCubeLayers(geometryDimension) {
  655. var geometry = geometryHelper.createBoxGeometry(geometryDimension, currentVolumeDimension);
  656. var colorArray = geometry.attributes.frontColor.array,
  657. positionArray = geometry.attributes.position.array;
  658. frontBox.geometry.attributes.frontColor.array = colorArray;
  659. frontBox.geometry.attributes.frontColor.needsUpdate = true;
  660. frontBox.geometry.attributes.position.array = positionArray;
  661. frontBox.geometry.attributes.position.needsUpdate = true;
  662. }
  663. // invert function of calculateLayerFloat
  664. function calculateLayerInt(position, dimMin, dimMax) {
  665. if(position <= 0.005) {
  666. return dimMin;
  667. }
  668. if(position >= 0.995) {
  669. return dimMax;
  670. }
  671. value = Math.round(position * (dimMax - dimMin) + dimMin);
  672. return value;
  673. }
  674. // calculate the float value for a layer input integer
  675. // 150 of [0, 299] will be 0.5
  676. function calculateLayerFloat(value, dimMin, dimMax) {
  677. var floatVal = (value - dimMin) / (dimMax - dimMin);
  678. if (floatVal == 0) {
  679. return 0.005;
  680. }
  681. if (floatVal == 1) {
  682. return 0.995;
  683. }
  684. return floatVal;
  685. }
  686. function calculateGrayFloat(value) {
  687. return value / 255.0;
  688. }
  689. function distance (v1, v2) {
  690. dx = v1.x - v2.x;
  691. dy = v1.y - v2.y;
  692. dz = v1.z - v2.z;
  693. return Math.sqrt(dx*dx+dy*dy+dz*dz);
  694. }
  695. function calculateWidthHeight() {
  696. downScaleFactor = 0.66;
  697. valueholder = {
  698. height: {},
  699. width: {}
  700. }
  701. containerHeight = $container.height();
  702. volumeInfoHeight = $('#volume-information').height();
  703. headerHeight = $('header').height();
  704. valueholder.height.px = (containerHeight - volumeInfoHeight) * downScaleFactor;
  705. volumeInfoHeightPercent = Math.floor(volumeInfoHeight / containerHeight * 100);
  706. valueholder.height.percent = 100 - volumeInfoHeightPercent;
  707. valueholder.width.px = $container.width() * downScaleFactor;
  708. valueholder.width.percent = 100;
  709. return valueholder;
  710. }
  711. function hideBottomControlsContainer() {
  712. var bottomControlsContainer = $('div#bottom-controls-container'),
  713. bottomControls = $('div#bottom-controls'),
  714. filledById = bottomControls.attr('filledBy'),
  715. filledBy = $('#' + filledById);
  716. // writing data back to original, because append MOVES the children
  717. if(filledBy.length == 1) {
  718. filledBy = $(filledBy[0]);
  719. filledByControlHolder = filledBy.children('.control-holder')[0];
  720. $(filledByControlHolder).append(bottomControls.children());
  721. }
  722. bottomControls.attr('filledBy', '');
  723. bottomControlsContainer.addClass('hidden');
  724. return filledById;
  725. }
  726. function addResolutionLinks() {
  727. $resSpan.text(config.defaultSize);
  728. textureSizes = config.textureSizes;
  729. textureSizes.forEach(function(size) {
  730. if(size > maximumTextureSize) {
  731. return;
  732. }
  733. href = size == config.defaultSize ? '' : 'href="#"';
  734. $resolutionLinks.append('<a '+href+' class="res-link" data="'+size+'">'+size+'</a> ');
  735. });
  736. }