Application.js 28 KB

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