Application.js 28 KB

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