|
@@ -0,0 +1,2398 @@
|
|
|
+var IPE = {
|
|
|
+ app : {},
|
|
|
+ helper : {},
|
|
|
+ interceptors : {}
|
|
|
+}
|
|
|
+
|
|
|
+String.prototype.endsWith = function(suffix) {
|
|
|
+ return this.indexOf(suffix, this.length - suffix.length) !== -1;
|
|
|
+};
|
|
|
+
|
|
|
+IPE.app = {
|
|
|
+ init : function(config) {
|
|
|
+ $.each(IPE.interceptors, function(index, interceptor) {
|
|
|
+ interceptor.init();
|
|
|
+ });
|
|
|
+
|
|
|
+ Globals.init();
|
|
|
+
|
|
|
+ IPE.app.initializeHelper();
|
|
|
+ IPE.app.bindEvents();
|
|
|
+ IPE.app.initData();
|
|
|
+
|
|
|
+ $resSpan.text(config.defaultSize);
|
|
|
+ textureSizes = config.textureSizes;
|
|
|
+ for (key in textureSizes) {
|
|
|
+ size = textureSizes[key];
|
|
|
+ href = size == config.defaultSize ? '' : 'href="#"';
|
|
|
+
|
|
|
+ $resLinkHolder.append('<a '+href+' class="res-link" data="'+size+'">'+size+'</a> ');
|
|
|
+ }
|
|
|
+
|
|
|
+ // Getting info file
|
|
|
+ $.ajax({
|
|
|
+ url: infoUrl + config.defaultSize,
|
|
|
+ success: function (data) {
|
|
|
+ textureInfo = data;
|
|
|
+
|
|
|
+ originalSizeArray[0] = textureInfo.originalSize.sizex;
|
|
|
+ originalSizeArray[1] = textureInfo.originalSize.sizey;
|
|
|
+ originalSizeArray[2] = textureInfo.originalSize.sizez;
|
|
|
+
|
|
|
+ imgInfo = data.info;
|
|
|
+
|
|
|
+ currentVolumeDimension.xmin = 0;
|
|
|
+ currentVolumeDimension.xmax = textureInfo.originalSize.sizex;
|
|
|
+ currentVolumeDimension.ymin = 0;
|
|
|
+ currentVolumeDimension.ymax = textureInfo.originalSize.sizey;
|
|
|
+ currentVolumeDimension.zmin = imgInfo.imgMin;
|
|
|
+ currentVolumeDimension.zmax = imgInfo.imgMax;
|
|
|
+
|
|
|
+ // downloading first image and starting
|
|
|
+ helper.downloadImage(spriteUrl + textureInfo.sprites[0][0].$oid, 0, 0, true);
|
|
|
+
|
|
|
+ $(document).trigger('basicsReady');
|
|
|
+ },
|
|
|
+ dataType: 'json'
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ container = document.getElementById( 'container' );
|
|
|
+ $container = $(container);
|
|
|
+ containerHeader = document.getElementById( 'container-header' );
|
|
|
+ $containerHeader = $(containerHeader);
|
|
|
+
|
|
|
+ containerOverview = document.getElementById('container-overview');
|
|
|
+ $containerOverview = $(containerOverview);
|
|
|
+
|
|
|
+ stats = new Stats();
|
|
|
+ $containerHeader.children('#container-stats').append( stats.domElement );
|
|
|
+
|
|
|
+ // until now, it has to be initialized here, needs a new internal structure
|
|
|
+ zoomHelper = new ZoomHelper();
|
|
|
+ },
|
|
|
+ initializeHelper: function() {
|
|
|
+ helper = new Helper();
|
|
|
+ geometryHelper = new GeometryHelper();
|
|
|
+ stepHelper = new StepHelper();
|
|
|
+ overviewHelper = new OverviewHelper();
|
|
|
+ transferHelper = new TransferHelper();
|
|
|
+ opacityPlotter = new OpacityPlotter();
|
|
|
+ },
|
|
|
+
|
|
|
+ initData: function() {
|
|
|
+ volumeId = $('#volumeId').val();
|
|
|
+
|
|
|
+ $resSpan = $('span#currentRes');
|
|
|
+ $resLinkHolder = $('#resolution-link-holder');
|
|
|
+
|
|
|
+ volumeUrl = homeUrl + 'volumes/' + volumeId + '/';
|
|
|
+ infoUrl = volumeUrl + 'texture-info/';
|
|
|
+ spriteUrl = volumeUrl + 'sprite/';
|
|
|
+
|
|
|
+ waitDiv = $('div#wait');
|
|
|
+
|
|
|
+ helper.initializeShaders(homeUrl + 'static/shaders/three-shader.vert', function(script) {
|
|
|
+ vertexShader = script
|
|
|
+ });
|
|
|
+ helper.initializeShaders(homeUrl + 'static/shaders/three-shader-simple.frag', function(script) {
|
|
|
+ fragmentSimleShader = script
|
|
|
+ });
|
|
|
+ helper.initializeShaders(homeUrl + 'static/shaders/three-shader.frag', function(script) {
|
|
|
+ fragmentShader = script
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ bindEvents : function() {
|
|
|
+ $(document).on('firstImageOnLoad',function (e, firstImageParams){
|
|
|
+ initTextures(imgInfo, firstImageParams, true);
|
|
|
+
|
|
|
+ initFrameControls();
|
|
|
+
|
|
|
+ stepHelper.initStepControls();
|
|
|
+
|
|
|
+ initSliders();
|
|
|
+ });
|
|
|
+
|
|
|
+ $(document).on('imageOnLoad', function(e, imageParams) {
|
|
|
+ initTextures(imgInfo, imageParams, false);
|
|
|
+
|
|
|
+ if(useDownloadedTextureImmediately) {
|
|
|
+ updateTexture();
|
|
|
+ useDownloadedTextureImmediately = false;
|
|
|
+ updateFrameControls();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ $(document).on('firstFrameSpritesCompleted', function() {
|
|
|
+ init();
|
|
|
+
|
|
|
+ overviewHelper.initOverview(containerOverview);
|
|
|
+
|
|
|
+ animate();
|
|
|
+ });
|
|
|
+
|
|
|
+ showPopup = false;
|
|
|
+ $('#save-canvas').click(function(e, params) {
|
|
|
+ if(params != undefined && params.source != undefined && params.source == 'animate-function') {
|
|
|
+ window.open(params.imageUrl);
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ saveImage = true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ $(window).on('resize', function() {
|
|
|
+ var rendererSizeHolder = calculateWidthHeight();
|
|
|
+ width = rendererSizeHolder.width.px;
|
|
|
+ height = rendererSizeHolder.height.px;
|
|
|
+
|
|
|
+ cameraRTT.aspect = width / height;
|
|
|
+ cameraRTT.updateProjectionMatrix();
|
|
|
+
|
|
|
+ camera.aspect = width / height;
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
+
|
|
|
+ renderer.setSize( width, height );
|
|
|
+ renderer.domElement.style.width = rendererSizeHolder.width.percent + '%';
|
|
|
+ renderer.domElement.style.height = rendererSizeHolder.height.percent + '%';
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ $('#resolution-link-holder').on('click', 'a', function(e) {
|
|
|
+ e.preventDefault();
|
|
|
+ e.stopPropagation();
|
|
|
+
|
|
|
+ if($(this).attr('href') == undefined) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ requestedSize = $(this).attr('data');
|
|
|
+
|
|
|
+ $('.res-link').each(function(index, value) {
|
|
|
+ $(value).attr('href', '#');
|
|
|
+ });
|
|
|
+ $(this).removeAttr('href');
|
|
|
+
|
|
|
+ $.ajax({
|
|
|
+ // todo test after remove of sync flag
|
|
|
+ url: infoUrl + requestedSize,
|
|
|
+ success: function (data) {
|
|
|
+ framesDownloaded = 0;
|
|
|
+ textures = {};
|
|
|
+ currentTexture = 0;
|
|
|
+
|
|
|
+ textureInfo = data;
|
|
|
+ imgInfo = data.info;
|
|
|
+ imgMin = imgInfo.imgMin;
|
|
|
+ imgMax = imgInfo.imgMax;
|
|
|
+ useDownloadedTextureImmediately = true;
|
|
|
+ helper.downloadImage(spriteUrl + textureInfo.sprites[0][0].$oid, 0, 0, false);
|
|
|
+ $resSpan.text(requestedSize);
|
|
|
+ },
|
|
|
+ dataType: 'json'
|
|
|
+ });
|
|
|
+
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+
|
|
|
+ $('div.controls').on('click', function() {
|
|
|
+ var $this = $(this),
|
|
|
+ controlFillerContainer = $('div#control-filler-container'),
|
|
|
+ controlFiller = $('div#control-filler'),
|
|
|
+ filledById = '',
|
|
|
+ thisControlHolder = null;
|
|
|
+
|
|
|
+ filledById = hideControlFillerContainer();
|
|
|
+ if(filledById === $this.attr('id')) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ thisControlHolder = $this.children('.control-holder')[0];
|
|
|
+ thisControlHolder = $(thisControlHolder);
|
|
|
+
|
|
|
+ controlFiller.append(thisControlHolder.children());
|
|
|
+ controlFiller.attr('filledBy', $this.attr('id'));
|
|
|
+ controlFillerContainer.removeClass('hidden');
|
|
|
+ });
|
|
|
+
|
|
|
+ $('input#hide-control-filler-container').on('click', function() {
|
|
|
+ hideControlFillerContainer();
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ $('div#menu-buttons-small-devices input').on('click', function() {
|
|
|
+ var $this = $(this),
|
|
|
+ target = $this.attr('data'),
|
|
|
+ $target = $('#' + target),
|
|
|
+ $overlay = $('div#overlay-small-devices'),
|
|
|
+ $content = $('div#content-small-devices');
|
|
|
+
|
|
|
+ $overlay.attr('source', target);
|
|
|
+ $content.append($target.children());
|
|
|
+ $overlay.show();
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ $('input#hide-content-small-devices').on('click', function() {
|
|
|
+ var $this = $(this)
|
|
|
+ $overlay = $('div#overlay-small-devices'),
|
|
|
+ $content = $('div#content-small-devices'),
|
|
|
+ source = $overlay.attr('source'),
|
|
|
+ $source = $('#' + source);
|
|
|
+
|
|
|
+ $overlay.hide();
|
|
|
+ $overlay.attr('source', '');
|
|
|
+ $source.append($content.children());
|
|
|
+ });
|
|
|
+
|
|
|
+ var buttonAdvCons = $('input#show-adv-con');
|
|
|
+ buttonAdvCons.on('click', function() {
|
|
|
+ var advCons = $('div#advanced-controls');
|
|
|
+
|
|
|
+ if(advCons.hasClass('hidden')) {
|
|
|
+ advCons.removeClass('hidden');
|
|
|
+ buttonAdvCons.val('hide adv cons');
|
|
|
+
|
|
|
+ } else {
|
|
|
+ advCons.addClass('hidden');
|
|
|
+ buttonAdvCons.val('show adv cons');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function initTextures(imgInfo, imageParams, whileInit) {
|
|
|
+ // set initial array to index
|
|
|
+ if(textures[imageParams.textureIndex] == undefined
|
|
|
+ || textures[imageParams.textureIndex] == null) {
|
|
|
+ textures[imageParams.textureIndex] = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // using texture
|
|
|
+ texture = initTexture(imageParams.texture);
|
|
|
+ textures[imageParams.textureIndex].push(texture);
|
|
|
+
|
|
|
+ // fetch new sprites of same time frame
|
|
|
+ if(imageParams.spriteIndex < imgInfo.numberOfSprites - 1) {
|
|
|
+ nextSpriteIndex = imageParams.spriteIndex + 1;
|
|
|
+ nextSpriteId = textureInfo.sprites[imageParams.textureIndex][nextSpriteIndex].$oid
|
|
|
+ helper.downloadImage(spriteUrl + nextSpriteId, imageParams.textureIndex, nextSpriteIndex, false);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // inform the rest, that the first frame is loaded completely
|
|
|
+ if(whileInit && imageParams.textureIndex == 0) {
|
|
|
+ $(document).trigger('firstFrameSpritesCompleted');
|
|
|
+ }
|
|
|
+
|
|
|
+ // todo some logic
|
|
|
+ if(!imgInfo.multipleFrames) {
|
|
|
+ currentTexture = 0;
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ var numberOfFrames = Object.keys(textureInfo.sprites).length,
|
|
|
+ nextIndex = null,
|
|
|
+ nextFrameName = null,
|
|
|
+ nextFramePath = null;
|
|
|
+
|
|
|
+ framesDownloaded++;
|
|
|
+
|
|
|
+ if(framesDownloaded == 1) {
|
|
|
+ currentTexture = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ currentMaxFrame = imgInfo.frameFrom + framesDownloaded - 1;
|
|
|
+
|
|
|
+ if(framesDownloaded > 1) {
|
|
|
+ // updating frame control maximums
|
|
|
+ updateFrameControlsMaxFrame();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(numberOfFrames == framesDownloaded) {
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ nextIndex = framesDownloaded;
|
|
|
+ nextFrameName = textureInfo.sprites[nextIndex].$oid;
|
|
|
+ var framePath = spriteUrl + nextFrameName;
|
|
|
+ helper.downloadImage(framePath, nextIndex, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function initTexture(texture) {
|
|
|
+ texture.magFilter = THREE.LinearFilter;
|
|
|
+ texture.minFilter = THREE.LinearFilter;
|
|
|
+ texture.needsUpdate = true;
|
|
|
+
|
|
|
+ return texture;
|
|
|
+}
|
|
|
+
|
|
|
+function getCurrentTexture() {
|
|
|
+ return textures[currentTexture];
|
|
|
+}
|
|
|
+
|
|
|
+function initFrameControls() {
|
|
|
+ if(!imgInfo.multipleFrames && (imgInfo.frameTo - imgInfo.frameFrom) > 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $('#frame-controls').removeClass('hidden');
|
|
|
+
|
|
|
+ var $frameSlider = $('#frame-slider'),
|
|
|
+ $playButton = $('#frame-play'),
|
|
|
+ $pauseButton = $('#frame-pause'),
|
|
|
+ $currentFrameInput = $('#currentFrame'),
|
|
|
+ playId = $playButton.attr('id'),
|
|
|
+ pauseId = $pauseButton.attr('id'),
|
|
|
+ minFrame = imgInfo.frameFrom;
|
|
|
+
|
|
|
+ $currentFrameInput.val(minFrame);
|
|
|
+ var play = function() {
|
|
|
+ if(Object.keys(textures).length == 1) {
|
|
|
+ console.warn('only one texture loaded, can not play yet');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $playButton.addClass('hidden');
|
|
|
+ $pauseButton.removeClass('hidden');
|
|
|
+ playFrames = true;
|
|
|
+ $frameSlider.slider({disabled: true});
|
|
|
+ $currentFrameInput.prop('disabled', true);
|
|
|
+ }
|
|
|
+ var pause = function() {
|
|
|
+ $playButton.removeClass('hidden');
|
|
|
+ $pauseButton.addClass('hidden');
|
|
|
+ playFrames = false;
|
|
|
+ $frameSlider.slider({disabled: false});
|
|
|
+ $currentFrameInput.prop('disabled', false);
|
|
|
+ }
|
|
|
+
|
|
|
+ $('.frame-button').click(function() {
|
|
|
+ var $this = $(this),
|
|
|
+ thisId = $this.attr('id');
|
|
|
+ if(thisId == playId) {
|
|
|
+ play();
|
|
|
+ } else if(thisId == pauseId) {
|
|
|
+ pause();
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ $(document).on('zoomActionFinished', function(e, params) {
|
|
|
+ zoomedIn = params.zoomAction == 'zoomIn';
|
|
|
+ if(zoomedIn) {
|
|
|
+ pause();
|
|
|
+ currentTexture = minFrame + params.textureNumber;
|
|
|
+ updateFrameControls();
|
|
|
+ $frameSlider.slider({disabled: true});
|
|
|
+ $currentFrameInput.prop('disabled', true);
|
|
|
+ $playButton.prop('disabled', true);
|
|
|
+ $pauseButton.prop('disabled', true);
|
|
|
+ } else {
|
|
|
+ $frameSlider.slider({disabled: false});
|
|
|
+ $currentFrameInput.prop('disabled', false);
|
|
|
+ $playButton.prop('disabled', false);
|
|
|
+ $pauseButton.prop('disabled', false);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ $frameSlider.slider(
|
|
|
+ {
|
|
|
+ min: minFrame,
|
|
|
+ max: currentMaxFrame,
|
|
|
+ slide: function( event, ui ) {
|
|
|
+ currentTexture = ui.value - minFrame;
|
|
|
+ updateTexture();
|
|
|
+ $currentFrameInput.val(ui.value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ $currentFrameInput.change(function() {
|
|
|
+ var value = parseInt($(this).val());
|
|
|
+ if(value >= imgInfo.frameFrom && currentMaxFrame >= value) {
|
|
|
+ currentTexture = value - minFrame;
|
|
|
+ updateTexture();
|
|
|
+ $frameSlider.slider('value', value);
|
|
|
+ } else {
|
|
|
+ $(this).val($frameSlider.slider('value'));
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function updateFrameControlsMaxFrame() {
|
|
|
+ if(!imgInfo.multipleFrames) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var $frameSlider = $('#frame-slider');
|
|
|
+
|
|
|
+ $frameSlider.slider('option', 'max', currentMaxFrame);
|
|
|
+}
|
|
|
+
|
|
|
+function updateFrameControls() {
|
|
|
+ if(!imgInfo.multipleFrames) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var $frameSlider = $('#frame-slider'),
|
|
|
+ $currentFrameInput = $('#currentFrame'),
|
|
|
+ minFrame = imgInfo.frameFrom,
|
|
|
+ value = currentTexture + minFrame;
|
|
|
+
|
|
|
+
|
|
|
+ $frameSlider.slider('value', value);
|
|
|
+ $currentFrameInput.val(value);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function init() {
|
|
|
+ $statsDom = $(stats.domElement);
|
|
|
+
|
|
|
+ rendererSizeHolder = calculateWidthHeight();
|
|
|
+
|
|
|
+ width = rendererSizeHolder.width.px;
|
|
|
+ height = rendererSizeHolder.height.px;
|
|
|
+
|
|
|
+ //width = window.innerWidth;
|
|
|
+ //height = window.innerHeight;
|
|
|
+
|
|
|
+ camera = new THREE.PerspectiveCamera( 45, width / height, .1, 1000 );
|
|
|
+ camera.position.z = 2;
|
|
|
+
|
|
|
+ cameraRTT = new THREE.PerspectiveCamera( 45, width / height, .1, 1000 );
|
|
|
+ cameraRTT.position.z = 2;
|
|
|
+
|
|
|
+ scene = new THREE.Scene();
|
|
|
+ sceneRTT = new THREE.Scene();
|
|
|
+
|
|
|
+ rtTexture = new THREE.WebGLRenderTarget( width, height, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat } );
|
|
|
+
|
|
|
+ var geometry = geometryHelper.createBoxGeometry(originalDimension);
|
|
|
+
|
|
|
+ var attributes = {
|
|
|
+ frontColor: {type: 'c', value: [] }
|
|
|
+ }
|
|
|
+
|
|
|
+ material = new THREE.ShaderMaterial({
|
|
|
+ attributes: attributes,
|
|
|
+ vertexShader: vertexShader,
|
|
|
+ fragmentShader: fragmentSimleShader,
|
|
|
+ side: THREE.FrontSide
|
|
|
+ });
|
|
|
+
|
|
|
+ var spriteMaps = getCurrentTexture();
|
|
|
+
|
|
|
+ var transferImageData = transferHelper.getCurrentTransferFunction();
|
|
|
+ var transferTexture = new THREE.Texture(transferImageData);
|
|
|
+ transferTexture.needsUpdate = true;
|
|
|
+
|
|
|
+ var uniforms = {
|
|
|
+ tBackground: {type: 't', value: rtTexture},
|
|
|
+ tvSlices: {type: 'tv', value: spriteMaps},
|
|
|
+ tTransfer: { type: 't', value: transferTexture},
|
|
|
+ minGray: {type: 'f', value: minGray },
|
|
|
+ maxGray: {type: 'f', value: maxGray },
|
|
|
+ steps: {type: 'f', value: 100},
|
|
|
+ numberOfSlices: {type: 'f', value: imgInfo.numberOfSlices },
|
|
|
+ numberOfSprites: {type: 'f', value: imgInfo.numberOfSprites },
|
|
|
+ slicesPerSprite: {type: 'f', value: imgInfo.slicesPerSprite },
|
|
|
+ slicesOverX: {type: 'f', value: imgInfo.slicesOverX },
|
|
|
+ slicesOverY: {type: 'f', value: imgInfo.slicesOverY },
|
|
|
+ };
|
|
|
+
|
|
|
+ materialScreen = new THREE.ShaderMaterial({
|
|
|
+ attributes: attributes,
|
|
|
+ uniforms: uniforms,
|
|
|
+ vertexShader: vertexShader,
|
|
|
+ fragmentShader: fragmentShader,
|
|
|
+ side: THREE.BackSide,
|
|
|
+ transparent: true
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ backgroundBox = new THREE.Mesh(geometry, material);
|
|
|
+ sceneRTT.add(backgroundBox);
|
|
|
+
|
|
|
+ frontBox = new THREE.Mesh(geometry, materialScreen);//
|
|
|
+ scene.add(frontBox);
|
|
|
+ objectsToIntersect.push(frontBox);
|
|
|
+
|
|
|
+ translateBoxes(-0.5, -0.5, -0.5);
|
|
|
+ rotateBoxesY(Math.PI);
|
|
|
+ rotateBoxesZ(Math.PI);
|
|
|
+
|
|
|
+ //renderer = new THREE.WebGLRenderer( { antialias: false, alpha: true });
|
|
|
+ renderer = new THREE.WebGLRenderer();
|
|
|
+ renderer.setSize(width, height);
|
|
|
+ renderer.domElement.style.width = rendererSizeHolder.width.percent + '%';
|
|
|
+ renderer.domElement.style.height = rendererSizeHolder.height.percent + '%';
|
|
|
+ renderer.setClearColor(0xffffff, 1);
|
|
|
+ container.appendChild(renderer.domElement);
|
|
|
+
|
|
|
+ $canvas = $('canvas', $container);
|
|
|
+
|
|
|
+ controls1 = new THREE.OrbitControls( camera, renderer.domElement );
|
|
|
+ controls1.damping = 0.2;
|
|
|
+
|
|
|
+ controls2 = new THREE.OrbitControls( cameraRTT, renderer.domElement );
|
|
|
+ controls2.damping = 0.2;
|
|
|
+
|
|
|
+ rendererContext = renderer.context;
|
|
|
+
|
|
|
+ raycaster = new THREE.Raycaster();
|
|
|
+}
|
|
|
+
|
|
|
+function rotateBoxesY(radian) {
|
|
|
+ rotationMatrix = new THREE.Matrix4().makeRotationY(radian);
|
|
|
+ rotateBoxes(rotationMatrix);
|
|
|
+}
|
|
|
+
|
|
|
+function rotateBoxesZ(radian) {
|
|
|
+ rotationMatrix = new THREE.Matrix4().makeRotationZ(radian);
|
|
|
+ rotateBoxes(rotationMatrix);
|
|
|
+}
|
|
|
+
|
|
|
+function rotateBoxes(matrix) {
|
|
|
+ backgroundBox.applyMatrix(rotationMatrix);
|
|
|
+ frontBox.applyMatrix(rotationMatrix);
|
|
|
+}
|
|
|
+
|
|
|
+function translateBoxes(x, y, z) {
|
|
|
+ translationMatrix = new THREE.Matrix4().makeTranslation(x, y, z);
|
|
|
+ backgroundBox.applyMatrix(translationMatrix);
|
|
|
+ frontBox.applyMatrix(translationMatrix);
|
|
|
+}
|
|
|
+
|
|
|
+function initSliders() {
|
|
|
+ initLayerSliders();
|
|
|
+
|
|
|
+ // init gray value slider
|
|
|
+ GenericSlider.initSlider(
|
|
|
+ slider = $( "#gray-slider" ),
|
|
|
+ sliderInputs = $('input.gray'),
|
|
|
+ minGray,
|
|
|
+ maxGray,
|
|
|
+ function(values) {
|
|
|
+ var minGray = calculateGrayFloat(values[0]),
|
|
|
+ maxGray = calculateGrayFloat(values[1]);
|
|
|
+ updateGrayBorders(minGray, maxGray);
|
|
|
+ }
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function initLayerSliders() {
|
|
|
+ // init xlayer slider
|
|
|
+ GenericSlider.initSlider(
|
|
|
+ $( "#xlayer-slider" ),
|
|
|
+ sliderInputs = $('input.xlayer'),
|
|
|
+ currentVolumeDimension.xmin,
|
|
|
+ currentVolumeDimension.xmax,
|
|
|
+ function(values) {
|
|
|
+ dimMin = currentVolumeDimension.xmin;
|
|
|
+ dimMax = currentVolumeDimension.xmax;
|
|
|
+ currentDimension.xmin = calculateLayerFloat(values[0], dimMin, dimMax);
|
|
|
+ currentDimension.xmax = calculateLayerFloat(values[1], dimMin, dimMax);
|
|
|
+ updateCubeLayers(currentDimension);
|
|
|
+ },
|
|
|
+ function() {
|
|
|
+ values = Array(2);
|
|
|
+ values[0] = calculateLayerInt(currentDimension.xmin, currentVolumeDimension.xmin, currentVolumeDimension.xmax );
|
|
|
+ values[1] = calculateLayerInt(currentDimension.xmax, currentVolumeDimension.xmin, currentVolumeDimension.xmax );
|
|
|
+
|
|
|
+ return values;
|
|
|
+ }
|
|
|
+ );
|
|
|
+ // init ylayer slider
|
|
|
+ GenericSlider.initSlider(
|
|
|
+ $( "#ylayer-slider" ),
|
|
|
+ sliderInputs = $('input.ylayer'),
|
|
|
+ currentVolumeDimension.ymin,
|
|
|
+ currentVolumeDimension.ymax,
|
|
|
+ function(values) {
|
|
|
+ dimMin = currentVolumeDimension.ymin;
|
|
|
+ dimMax = currentVolumeDimension.ymax;
|
|
|
+ currentDimension.ymin = calculateLayerFloat(values[0], dimMin, dimMax);
|
|
|
+ currentDimension.ymax = calculateLayerFloat(values[1], dimMin, dimMax);
|
|
|
+ updateCubeLayers(currentDimension);
|
|
|
+ },
|
|
|
+ function() {
|
|
|
+ values = Array(2);
|
|
|
+ values[0] = calculateLayerInt(currentDimension.ymin, currentVolumeDimension.ymin, currentVolumeDimension.ymax );
|
|
|
+ values[1] = calculateLayerInt(currentDimension.ymax, currentVolumeDimension.ymin, currentVolumeDimension.ymax );
|
|
|
+
|
|
|
+ return values;
|
|
|
+ }
|
|
|
+ );
|
|
|
+ // init zlayer slider
|
|
|
+ GenericSlider.initSlider(
|
|
|
+ $( "#zlayer-slider" ),
|
|
|
+ sliderInputs = $('input.zlayer'),
|
|
|
+ currentVolumeDimension.zmin,
|
|
|
+ currentVolumeDimension.zmax,
|
|
|
+ function(values) {
|
|
|
+ dimMin = currentVolumeDimension.zmin;
|
|
|
+ dimMax = currentVolumeDimension.zmax;
|
|
|
+ currentDimension.zmin = calculateLayerFloat(values[0], dimMin, dimMax),
|
|
|
+ currentDimension.zmax = calculateLayerFloat(values[1], dimMin, dimMax);
|
|
|
+ updateCubeLayers(currentDimension);
|
|
|
+ },
|
|
|
+ function() {
|
|
|
+ values = Array(2);
|
|
|
+ values[0] = calculateLayerInt(currentDimension.zmin, currentVolumeDimension.zmin, currentVolumeDimension.zmax );
|
|
|
+ values[1] = calculateLayerInt(currentDimension.zmax, currentVolumeDimension.zmin, currentVolumeDimension.zmax );
|
|
|
+
|
|
|
+ return values;
|
|
|
+ }
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function repositionLayerSliders() {
|
|
|
+ initLayerSliders();
|
|
|
+
|
|
|
+ $.each($('.slider.layer'), function(index, value) {
|
|
|
+ $(value).trigger('reposition');
|
|
|
+ });
|
|
|
+ updateCubeLayers(currentDimension);
|
|
|
+}
|
|
|
+
|
|
|
+var prevTime = Date.now();
|
|
|
+var fps = 0;
|
|
|
+var frames = 0;
|
|
|
+
|
|
|
+
|
|
|
+function animate() {
|
|
|
+ requestAnimationFrame( animate );
|
|
|
+
|
|
|
+
|
|
|
+ $container.trigger('animation');
|
|
|
+
|
|
|
+ var numberOfTextures = Object.keys(textures).length;
|
|
|
+ var now = Date.now();
|
|
|
+ frames++;
|
|
|
+
|
|
|
+ if(now > prevTime + 1000) {
|
|
|
+ fps = (frames * 1000) / (now - prevTime);
|
|
|
+ if(adjustSteps) {
|
|
|
+ if(fps < 10) {
|
|
|
+ stepHelper.decreaseSteps();
|
|
|
+ } else if(fps > 15) {
|
|
|
+ stepHelper.increaseSteps();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ prevTime = now;
|
|
|
+ frames = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(playFrames && numberOfTextures > 1) {
|
|
|
+
|
|
|
+ var timeStamp = (new Date()).getTime();
|
|
|
+ if(timeStamp - textureTimestamp > 400) {
|
|
|
+ currentTexture++;
|
|
|
+ if(currentTexture >= numberOfTextures) {
|
|
|
+ currentTexture = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ updateTexture();
|
|
|
+ textureTimestamp = timeStamp;
|
|
|
+ updateFrameControls();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(nextCubeDeletionTimeStamp == null && intersectCubesTimeStamps.length != 0) {
|
|
|
+ nextCubeDeletionTimeStamp = intersectCubesTimeStamps.shift();
|
|
|
+ }
|
|
|
+
|
|
|
+ if((Date.now() - nextCubeDeletionTimeStamp) > 1500) {
|
|
|
+ cubeToDelete = intersectCubes.shift();
|
|
|
+ scene.remove(cubeToDelete);
|
|
|
+
|
|
|
+ nextCubeDeletionTimeStamp = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(transferHelper.transferFunctionChanged()) {
|
|
|
+ var transfer = new THREE.Texture(transferHelper.getCurrentTransferFunction());
|
|
|
+ transfer.needsUpdate = true;
|
|
|
+ materialScreen.uniforms.tTransfer.value = transfer;
|
|
|
+ }
|
|
|
+
|
|
|
+ cameraPoint = camera.position.clone();
|
|
|
+ overviewHelper.updateCameraPosition(cameraPoint);
|
|
|
+
|
|
|
+ stats.update();
|
|
|
+ controls1.update();
|
|
|
+ controls2.update();
|
|
|
+
|
|
|
+ render();
|
|
|
+ if(saveImage) {
|
|
|
+ $('#save-canvas').trigger('click', { source: 'animate-function', imageUrl: renderer.domElement.toDataURL() });
|
|
|
+ saveImage = false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+function updateTexture(textures) {
|
|
|
+ if(textures == undefined || textures == null) {
|
|
|
+ textures = getCurrentTexture();
|
|
|
+ }
|
|
|
+ $.each(textures, function(index, texture) {
|
|
|
+ value.needsUpdate = true;
|
|
|
+ });
|
|
|
+
|
|
|
+ materialScreen.uniforms.tvSlices.value = textures;
|
|
|
+}
|
|
|
+
|
|
|
+function render() {
|
|
|
+ renderer.clear();
|
|
|
+
|
|
|
+ renderer.context.clearDepth(-50.0);
|
|
|
+ renderer.context.depthFunc(renderer.context.GEQUAL);
|
|
|
+ renderer.render(sceneRTT, cameraRTT, rtTexture, true);
|
|
|
+
|
|
|
+ renderer.context.clearDepth(50.0);
|
|
|
+ renderer.context.depthFunc(renderer.context.LEQUAL);
|
|
|
+ renderer.render(scene, camera);
|
|
|
+
|
|
|
+ overviewHelper.render();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function updateCubeLayers(geometryDimension) {
|
|
|
+ var geometry = geometryHelper.createBoxGeometry(geometryDimension);
|
|
|
+ var colorArray = geometry.attributes.frontColor.array,
|
|
|
+ positionArray = geometry.attributes.position.array;
|
|
|
+
|
|
|
+ frontBox.geometry.attributes.frontColor.array = colorArray;
|
|
|
+ frontBox.geometry.attributes.frontColor.needsUpdate = true;
|
|
|
+ frontBox.geometry.attributes.position.array = positionArray;
|
|
|
+ frontBox.geometry.attributes.position.needsUpdate = true;
|
|
|
+}
|
|
|
+
|
|
|
+function updateGrayBorders(minGray, maxGray) {
|
|
|
+ materialScreen.uniforms.minGray.value = minGray;
|
|
|
+ materialScreen.uniforms.maxGray.value = maxGray;
|
|
|
+}
|
|
|
+
|
|
|
+// invert function of calculateLayerFloat
|
|
|
+function calculateLayerInt(position, dimMin, dimMax) {
|
|
|
+ if(position <= 0.005) {
|
|
|
+ return dimMin;
|
|
|
+ }
|
|
|
+ if(position >= 0.995) {
|
|
|
+ return dimMax;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Math.round(position * (dimMax - dimMin) + dimMin);
|
|
|
+}
|
|
|
+
|
|
|
+// calculate the float value for a layer input integer
|
|
|
+// 150 of [0, 299] will be 0.5
|
|
|
+function calculateLayerFloat(value, dimMin, dimMax) {
|
|
|
+ var floatVal = (value - dimMin) / (dimMax - dimMin);
|
|
|
+
|
|
|
+ if (floatVal == 0) {
|
|
|
+ return 0.005;
|
|
|
+ }
|
|
|
+ if (floatVal == 255) {
|
|
|
+ return 0.995;
|
|
|
+ }
|
|
|
+
|
|
|
+ return floatVal;
|
|
|
+}
|
|
|
+
|
|
|
+function calculateGrayFloat(value) {
|
|
|
+ return value / 255.0;
|
|
|
+}
|
|
|
+
|
|
|
+function distance (v1, v2) {
|
|
|
+ dx = v1.x - v2.x;
|
|
|
+ dy = v1.y - v2.y;
|
|
|
+ dz = v1.z - v2.z;
|
|
|
+
|
|
|
+ return Math.sqrt(dx*dx+dy*dy+dz*dz);
|
|
|
+}
|
|
|
+
|
|
|
+function calculateWidthHeight() {
|
|
|
+ downScaleFactor = 0.66;
|
|
|
+ valueholder = {
|
|
|
+ height: {},
|
|
|
+ width: {}
|
|
|
+ }
|
|
|
+ containerHeight = $container.height();
|
|
|
+ volumeInfoHeight = $('#volume-information').height();
|
|
|
+ valueholder.height.px = (containerHeight - volumeInfoHeight) * downScaleFactor;
|
|
|
+ volumeInfoHeightPercent = Math.floor(volumeInfoHeight / containerHeight * 100);
|
|
|
+ valueholder.height.percent = 100 - volumeInfoHeightPercent;
|
|
|
+
|
|
|
+ valueholder.width.px = $container.width() * downScaleFactor;
|
|
|
+ valueholder.width.percent = 100;
|
|
|
+
|
|
|
+ return valueholder;
|
|
|
+}
|
|
|
+
|
|
|
+function hideControlFillerContainer() {
|
|
|
+ var controlFillerContainer = $('div#control-filler-container'),
|
|
|
+ controlFiller = $('div#control-filler'),
|
|
|
+ filledById = controlFiller.attr('filledBy'),
|
|
|
+ filledBy = $('#' + filledById);
|
|
|
+
|
|
|
+ // writing data back to original, because append MOVES the children
|
|
|
+ if(filledBy.length == 1) {
|
|
|
+ filledBy = $(filledBy[0]);
|
|
|
+ filledByControlHolder = filledBy.children('.control-holder')[0];
|
|
|
+ $(filledByControlHolder).append(controlFiller.children());
|
|
|
+ }
|
|
|
+
|
|
|
+ controlFiller.attr('filledBy', '');
|
|
|
+ controlFillerContainer.addClass('hidden');
|
|
|
+
|
|
|
+ return filledById;
|
|
|
+}
|
|
|
+;var volumeId;
|
|
|
+var stats, container, $container, containerHeader, $containerHeader, $canvas, cameraRTT, camera, sceneRTT, scene, renderer, controls, controls2;
|
|
|
+var containerOverview, $containerOverview;
|
|
|
+var $resSpan;
|
|
|
+var $resLinkHolder;
|
|
|
+var raycaster;
|
|
|
+var width, height;
|
|
|
+var steps, adjustSteps;
|
|
|
+var rtTexture, material;
|
|
|
+
|
|
|
+var backgroundBox, frontBox;
|
|
|
+var objectsToIntersect = [];
|
|
|
+var minGray = 0, maxGray = 255;
|
|
|
+var originalDimension,
|
|
|
+ zoomedDimension,
|
|
|
+ currentDimension,
|
|
|
+ originalVolumeDimension,
|
|
|
+ zoomedVolumeDimension,
|
|
|
+ currentVolumeDimension,
|
|
|
+ volumeUrl,
|
|
|
+ infoUrl,
|
|
|
+ spriteUrl,
|
|
|
+ imgInfo = null,
|
|
|
+ textureInfo = null,
|
|
|
+ originalSizeArray = Array(3),
|
|
|
+ zoomedInfo;
|
|
|
+
|
|
|
+var textures = {},
|
|
|
+ currentTexture = 0,
|
|
|
+ useDownloadedTextureImmediately = false,
|
|
|
+ textureTimestamp = (new Date()).getTime(),
|
|
|
+ playFrames = false,
|
|
|
+ currentMaxFrame = 0;
|
|
|
+
|
|
|
+var framesDownloaded = 0,
|
|
|
+ cachedImages = {};
|
|
|
+
|
|
|
+var vertexShader = null,
|
|
|
+ fragmentSimleShader = null,
|
|
|
+ fragmentShader = null;
|
|
|
+
|
|
|
+var intersectCubes = [],
|
|
|
+ intersectCubesTimeStamps = []
|
|
|
+ nextCubeDeletionTimeStamp = null,
|
|
|
+ zoomedIn = false;
|
|
|
+
|
|
|
+var helper,
|
|
|
+ geometryHelper,
|
|
|
+ stepHelper,
|
|
|
+ overviewHelper,
|
|
|
+ transferHelper,
|
|
|
+ zoomHelper,
|
|
|
+ opacityPlotter;
|
|
|
+
|
|
|
+var waitDiv;
|
|
|
+var saveImage = false;
|
|
|
+
|
|
|
+// prefetch first image to cache it
|
|
|
+var progressContainer,
|
|
|
+ imageProgress,
|
|
|
+ progressSpan;
|
|
|
+
|
|
|
+var Globals = (function() {
|
|
|
+ return {
|
|
|
+ init: function() {
|
|
|
+ originalDimension = new GeometryDimension();
|
|
|
+ zoomedDimension = new GeometryDimension();
|
|
|
+ currentDimension = originalDimension;
|
|
|
+ originalVolumeDimension = new VolumeDimension();
|
|
|
+ zoomedVolumeDimension = new VolumeDimension();
|
|
|
+ currentVolumeDimension = originalVolumeDimension;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}());
|
|
|
+;var GeometryHelper = function() {
|
|
|
+ return {
|
|
|
+ createBoxGeometry: function(dimension) {
|
|
|
+ var vertexPos = [
|
|
|
+ //front face first
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmax],
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmax],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmax],
|
|
|
+ //front face second
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmax],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmax],
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmax],
|
|
|
+
|
|
|
+ // back face first
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmin],
|
|
|
+ // back face second
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmin],
|
|
|
+
|
|
|
+ // top face first
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmin],
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmax],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmax],
|
|
|
+ // top face second
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmax],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmin],
|
|
|
+
|
|
|
+ // bottom face first
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmax],
|
|
|
+ // bottom face second
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmax],
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmax],
|
|
|
+
|
|
|
+ // right face first
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmax],
|
|
|
+ // right face second
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmax, dimension.ymax, dimension.zmax],
|
|
|
+ [dimension.xmax, dimension.ymin, dimension.zmax],
|
|
|
+
|
|
|
+ // left face first
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmax],
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmax],
|
|
|
+ // left face second
|
|
|
+ [dimension.xmin, dimension.ymin, dimension.zmin],
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmax],
|
|
|
+ [dimension.xmin, dimension.ymax, dimension.zmin]
|
|
|
+ ];
|
|
|
+
|
|
|
+ var positions = [];
|
|
|
+ var colors = [];
|
|
|
+
|
|
|
+ for(var i = 0; i < vertexPos.length; i++) {
|
|
|
+ var backCounter = vertexPos.length - 1 - i,
|
|
|
+ x = vertexPos[backCounter][0],
|
|
|
+ y = vertexPos[backCounter][1],
|
|
|
+ z = vertexPos[backCounter][2];
|
|
|
+
|
|
|
+ positions.push(x);
|
|
|
+ positions.push(y);
|
|
|
+ positions.push(z);
|
|
|
+
|
|
|
+ colors.push(x);
|
|
|
+ colors.push(y);
|
|
|
+ colors.push(z);
|
|
|
+ colors.push(1.0);
|
|
|
+ }
|
|
|
+
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
+ var bufferPositions = new Float32Array(positions);
|
|
|
+ geometry.addAttribute( 'position', new THREE.BufferAttribute( bufferPositions, 3 ) );
|
|
|
+ geometry.addAttribute( 'frontColor', new THREE.BufferAttribute(new Float32Array(colors), 4));
|
|
|
+ geometry.computeBoundingSphere();
|
|
|
+
|
|
|
+ return geometry;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+var GeometryDimension = function() {
|
|
|
+ this.xmin = 0.005;
|
|
|
+ this.xmax = 0.995;
|
|
|
+ this.ymin = 0.005;
|
|
|
+ this.ymax = 0.995;
|
|
|
+ this.zmin = 0.005;
|
|
|
+ this.zmax = 0.995;
|
|
|
+}
|
|
|
+
|
|
|
+var VolumeDimension = function() {
|
|
|
+ this.xmin;
|
|
|
+ this.xmax;
|
|
|
+ this.ymin;
|
|
|
+ this.ymax;
|
|
|
+ this.zmin;
|
|
|
+ this.zmax;
|
|
|
+}
|
|
|
+;var Helper = function() {
|
|
|
+ var messagePopup = $('#popup'),
|
|
|
+ popupVisible = messagePopup.hasClass('hidden'),
|
|
|
+ progressContainer = $('#progress-container'),
|
|
|
+ imageProgress = $('#image-progress'),
|
|
|
+ progressSpan = $('#texturePath');
|
|
|
+
|
|
|
+ return {
|
|
|
+ initializeShaders: function(url, callback) {
|
|
|
+ $.ajax({
|
|
|
+ url: url,
|
|
|
+ error: function() {
|
|
|
+ console.error('failed to load shader file from: ' + url);
|
|
|
+ },
|
|
|
+ success: callback
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ downloadImage: function (texturePath, textureIndex, spriteIndex, whileInit) {
|
|
|
+ progressContainer.removeClass('hidden');
|
|
|
+ progressSpan.text(texturePath);
|
|
|
+
|
|
|
+ if(!texturePath.endsWith('/')) {
|
|
|
+ texturePath += '/';
|
|
|
+ }
|
|
|
+
|
|
|
+ var xmlHttp = new XMLHttpRequest();
|
|
|
+ xmlHttp.open('GET', texturePath, true);
|
|
|
+ xmlHttp.onprogress = function(e) {
|
|
|
+ if (e.lengthComputable) {
|
|
|
+ value = Math.floor(e.loaded / e.total * 100);
|
|
|
+ imageProgress.val(value);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ xmlHttp.onload = function(e) {
|
|
|
+ var blob = new Blob([xmlHttp.response], {
|
|
|
+ type: this.getResponseHeader('content-type')
|
|
|
+ });
|
|
|
+
|
|
|
+ var blobSrc = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ var image = new Image();
|
|
|
+ var texture = new THREE.Texture(image);
|
|
|
+
|
|
|
+ image.onload = function() {
|
|
|
+ imageProgress.val(0);
|
|
|
+ progressSpan.text('');
|
|
|
+ progressContainer.addClass('hidden');
|
|
|
+
|
|
|
+ texture.needsUpdate = true;
|
|
|
+ var params = {
|
|
|
+ textureIndex: textureIndex,
|
|
|
+ spriteIndex: spriteIndex,
|
|
|
+ texture: texture
|
|
|
+ };
|
|
|
+
|
|
|
+ if(textureIndex == 0 && whileInit) {
|
|
|
+ $(document).trigger('firstImageOnLoad', params);
|
|
|
+ } else {
|
|
|
+ $(document).trigger('imageOnLoad', params);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ image.src = blobSrc;
|
|
|
+ };
|
|
|
+
|
|
|
+ xmlHttp.responseType = 'blob';
|
|
|
+ xmlHttp.send();
|
|
|
+ },
|
|
|
+
|
|
|
+ displayMessage: function(message, fadeOutAutomatically, callback, timeout) {
|
|
|
+ var me = this;
|
|
|
+ console.log('display messge');
|
|
|
+ messagePopup.html(message);
|
|
|
+ messagePopup.show();
|
|
|
+
|
|
|
+ if(fadeOutAutomatically) {
|
|
|
+ this.fadeoutMessage(callback, timeout);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ fadeoutMessage: function(callback, timeout) {
|
|
|
+ if(timeout == undefined) {
|
|
|
+ timeout = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ setTimeout(function() {
|
|
|
+ messagePopup.fadeOut(400, function() {
|
|
|
+ $(this).html('');
|
|
|
+ if(callback) {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }, timeout);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ };
|
|
|
+}
|
|
|
+;var OpacityPlotter = function() {
|
|
|
+
|
|
|
+ var opacities = Array(255);
|
|
|
+ var height = 40;
|
|
|
+ for(counter = 0; counter < 255; counter++) {
|
|
|
+ opacities[counter] = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ var stage = new Kinetic.Stage({
|
|
|
+ container : 'opacity-plot',
|
|
|
+ width : 255,
|
|
|
+ height: height
|
|
|
+ });
|
|
|
+
|
|
|
+ var layer = new Kinetic.Layer();
|
|
|
+ var rect = new Kinetic.Rect({
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: stage.getWidth(),
|
|
|
+ height: stage.getHeight(),
|
|
|
+ fill: '#cccccc'
|
|
|
+ });
|
|
|
+ layer.add(rect);
|
|
|
+
|
|
|
+ var spline = new Kinetic.Line({
|
|
|
+ points: [0, 0, 255, 0],
|
|
|
+ stroke: 'red',
|
|
|
+ strokeWidth: 3,
|
|
|
+ lineCap: 'round'
|
|
|
+ });
|
|
|
+ layer.add(spline);
|
|
|
+
|
|
|
+ stage.add(layer);
|
|
|
+
|
|
|
+ var calculateOpacities = function(points) {
|
|
|
+ var opacityCounter = 0;
|
|
|
+ for(counter = 2; counter < points.length; counter += 2) {
|
|
|
+ var x1 = points[counter - 2],
|
|
|
+ y1 = points[counter - 1],
|
|
|
+ x2 = points[counter],
|
|
|
+ y2 = points[counter + 1],
|
|
|
+ y1Height = (height - y1) / height,
|
|
|
+ y2Height = (height - y2) / height,
|
|
|
+ dy = (y2Height - y1Height) / (x2 - x1),
|
|
|
+ currentHeight = y1Height;
|
|
|
+
|
|
|
+ opacities[x1] = y1Height;
|
|
|
+
|
|
|
+ for(opacityCounter = (x1 + 1); opacityCounter <= x2; opacityCounter++) {
|
|
|
+ currentHeight += dy;
|
|
|
+ if(currentHeight < 0.0) {
|
|
|
+ currentHeight = 0.0;
|
|
|
+ } else if(currentHeight > 1.0) {
|
|
|
+ currentHeight = 1.0;
|
|
|
+ }
|
|
|
+ opacities[opacityCounter] = currentHeight * 255;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ stage.on("mousedown", function() {
|
|
|
+ var mousePos = stage.getPointerPosition(),
|
|
|
+ points = spline.getPoints(),
|
|
|
+ pointsLength = points.length;
|
|
|
+
|
|
|
+ for(counter = 0; counter < pointsLength; counter += 2) {
|
|
|
+ if(points[counter] == mousePos.x){
|
|
|
+ points[counter + 1] = mousePos.y;
|
|
|
+ } else if(points[counter] > mousePos.x) {
|
|
|
+ points.splice(counter, 0, mousePos.x);
|
|
|
+ points.splice(counter + 1, 0, mousePos.y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ calculateOpacities(points);
|
|
|
+ $(document).trigger('opacityChanged', { opacities: opacities });
|
|
|
+ spline.setPoints(points);
|
|
|
+ layer.draw();
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+;var OverviewHelper = function() {
|
|
|
+ var sceneOveriew, rendererOverview, cameraOverview, innerCubeOverview;
|
|
|
+
|
|
|
+ //private method
|
|
|
+ var addInnerCubeOverView = function(x, y, z) {
|
|
|
+ var innerCubeGeometry = new THREE.BoxGeometry( x, y, z );
|
|
|
+ var innerCubeMaterial = new THREE.MeshBasicMaterial( {color: 0xaaaaaa} );
|
|
|
+ innerCubeOverview = new THREE.Mesh( innerCubeGeometry, innerCubeMaterial );
|
|
|
+ sceneOverview.add( innerCubeOverview );
|
|
|
+ }
|
|
|
+
|
|
|
+ var initiateEventListener = function() {
|
|
|
+ // change overview box
|
|
|
+ $(document).on('zoomActionFinished', function(e, params) {
|
|
|
+
|
|
|
+ zoomedIn = params.zoomAction == 'zoomIn';
|
|
|
+ sceneOverview.remove(innerCubeOverview);
|
|
|
+
|
|
|
+ if(zoomedIn) {
|
|
|
+ xWidth = zoomedInfo.dimension.xywidth / textureInfo.originalSize.sizex;
|
|
|
+ yWidth = zoomedInfo.dimension.xywidth / textureInfo.originalSize.sizey;
|
|
|
+ zWidth = zoomedInfo.numberOfSlices / textureInfo.originalSize.sizez;
|
|
|
+
|
|
|
+ xOffset = zoomedInfo.dimension.xmin / textureInfo.originalSize.sizex;
|
|
|
+ yOffset = zoomedInfo.dimension.ymin / textureInfo.originalSize.sizey;
|
|
|
+ zOffset = zoomedInfo.dimension.zmin / textureInfo.info.numberOfSlices;
|
|
|
+
|
|
|
+ addInnerCubeOverView(xWidth, yWidth, zWidth);
|
|
|
+
|
|
|
+ innerCubeOverview.position.x = -0.5 + xOffset + xWidth / 2;
|
|
|
+ innerCubeOverview.position.y = (-0.5 + yOffset + yWidth / 2) * -1;
|
|
|
+ innerCubeOverview.position.z = (-0.5 + zOffset + zWidth / 2) * -1;
|
|
|
+ } else {
|
|
|
+ addInnerCubeOverView(1,1,1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ var addTextsToScene = function() {
|
|
|
+ var shapeParameters = {font: 'helvetiker', size: 0.2, height: 0.05},
|
|
|
+ shape = new THREE.TextGeometry("0", shapeParameters),
|
|
|
+ wrapper = new THREE.MeshBasicMaterial({color: 0x000000}),
|
|
|
+ words = new THREE.Mesh(shape, wrapper);
|
|
|
+
|
|
|
+ words.position.x = -0.6;
|
|
|
+ words.position.y = 0.52;
|
|
|
+ words.position.z = 0.52;
|
|
|
+ sceneOverview.add(words);
|
|
|
+ }
|
|
|
+
|
|
|
+ var addCubeEdges = function() {
|
|
|
+ // fix for cube
|
|
|
+ var numberOfEdges = 12;
|
|
|
+ var xColorEdge = new THREE.Color(1,0,0);
|
|
|
+ var yColorEdge = new THREE.Color(0,1,0);
|
|
|
+ var zColorEdge = new THREE.Color(0,0,1);
|
|
|
+
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
+ var material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors });
|
|
|
+
|
|
|
+ var colors = new Float32Array( numberOfEdges * 2 * 3 );
|
|
|
+ var positions = new Float32Array([
|
|
|
+ // edges in x direction
|
|
|
+ // front face
|
|
|
+ -0.5, -0.5, -0.5, 0.5, -0.5, -0.5,
|
|
|
+ -0.5, 0.5, -0.5, 0.5, 0.5, -0.5,
|
|
|
+ // back face
|
|
|
+ -0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
|
|
|
+ -0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
|
|
|
+
|
|
|
+ // edges in y direction
|
|
|
+ // front face
|
|
|
+ -0.5, -0.5, -0.5, -0.5, 0.5, -0.5,
|
|
|
+ 0.5, -0.5, -0.5, 0.5, 0.5, -0.5,
|
|
|
+ // back face
|
|
|
+ -0.5, -0.5, 0.5, -0.5, 0.5, 0.5,
|
|
|
+ 0.5, -0.5, 0.5, 0.5, 0.5, 0.5,
|
|
|
+
|
|
|
+ // edges in z direction
|
|
|
+ // left side
|
|
|
+ -0.5, -0.5, -0.5, -0.5, -0.5, 0.5,
|
|
|
+ -0.5, 0.5, -0.5, -0.5, 0.5, 0.5,
|
|
|
+ // right side
|
|
|
+ 0.5, -0.5, -0.5, 0.5, -0.5, 0.5,
|
|
|
+ 0.5, 0.5, -0.5, 0.5, 0.5, 0.5
|
|
|
+ ]);
|
|
|
+
|
|
|
+ for(edgeCounter = 0; edgeCounter < 12 * 2; edgeCounter++) {
|
|
|
+ var colorToUse = null
|
|
|
+ if(edgeCounter <= 7) {
|
|
|
+ colorToUse = xColorEdge;
|
|
|
+ } else if(edgeCounter <= 15) {
|
|
|
+ colorToUse = yColorEdge;
|
|
|
+ } else {
|
|
|
+ colorToUse = zColorEdge;
|
|
|
+ }
|
|
|
+
|
|
|
+ colors[edgeCounter * 3 + 0] = colorToUse.r;
|
|
|
+ colors[edgeCounter * 3 + 1] = colorToUse.g;
|
|
|
+ colors[edgeCounter * 3 + 2] = colorToUse.b;
|
|
|
+ }
|
|
|
+
|
|
|
+ geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
|
|
|
+ geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
|
|
|
+
|
|
|
+ var lines = new THREE.Line( geometry, material, THREE.LinePieces );
|
|
|
+ sceneOverview.add( lines );
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ initOverview: function(containerOverviewElement) {
|
|
|
+ sceneOverview = new THREE.Scene();
|
|
|
+ cameraOverview = new THREE.PerspectiveCamera( 45, 150 / 150, .1, 1000 );
|
|
|
+ cameraOverview.position.z = 2;
|
|
|
+
|
|
|
+ var cubeGeometry = new THREE.BoxGeometry( 1, 1, 1 );
|
|
|
+ var cubeMaterial = new THREE.MeshBasicMaterial( {color: 0x000000} );
|
|
|
+ var cubeOverview = new THREE.Mesh( cubeGeometry, cubeMaterial );
|
|
|
+ var edgesHelper = new THREE.EdgesHelper(cubeOverview, 0x000000);
|
|
|
+ edgesHelper.material.linewidth = 2;
|
|
|
+ //sceneOverview.add( edgesHelper );
|
|
|
+
|
|
|
+ addInnerCubeOverView(1,1,1);
|
|
|
+ addCubeEdges();
|
|
|
+ addTextsToScene();
|
|
|
+
|
|
|
+ rendererOverview = new THREE.WebGLRenderer();
|
|
|
+ rendererOverview.setSize(200, 200);
|
|
|
+ rendererOverview.setClearColor(0xffffff, 1);
|
|
|
+ containerOverviewElement.appendChild(rendererOverview.domElement);
|
|
|
+
|
|
|
+ initiateEventListener();
|
|
|
+ },
|
|
|
+
|
|
|
+ updateCameraPosition: function(position) {
|
|
|
+ cameraPoint.normalize().multiplyScalar(4);
|
|
|
+ cameraPoint = sceneOverview.position.clone().add(cameraPoint);
|
|
|
+
|
|
|
+ cameraOverview.position.x = cameraPoint.x;
|
|
|
+ cameraOverview.position.y = cameraPoint.y;
|
|
|
+ cameraOverview.position.z = cameraPoint.z;
|
|
|
+ cameraOverview.lookAt(sceneOverview.position);
|
|
|
+ },
|
|
|
+
|
|
|
+ render: function() {
|
|
|
+ rendererOverview.render(sceneOverview, cameraOverview);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+;var StepHelper = function() {
|
|
|
+ // default is the step 100
|
|
|
+ currentStepIndex = 2;
|
|
|
+ // steps just defined
|
|
|
+ availableSteps = [10, 20, 50, 80, 100, 150, 200];
|
|
|
+
|
|
|
+ return {
|
|
|
+ decreaseSteps: function() {
|
|
|
+ var currentStepIndex = this.determineCurrentStepIndex();
|
|
|
+
|
|
|
+ if(currentStepIndex > 0) {
|
|
|
+ this.updateStepValue(availableSteps[currentStepIndex - 1], true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ increaseSteps: function() {
|
|
|
+ var currentStepIndex = this.determineCurrentStepIndex();
|
|
|
+
|
|
|
+ if(currentStepIndex > -1 && currentStepIndex < availableSteps.length - 1) {
|
|
|
+ this.updateStepValue(availableSteps[currentStepIndex + 1], true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ determineCurrentStepIndex: function() {
|
|
|
+ var minDeviation = null,
|
|
|
+ minDeviationIndex;
|
|
|
+
|
|
|
+ // first we have to find an appropiate predefined stepValue for input stepvalue
|
|
|
+ for(var index = 0; index < availableSteps.length; index++) {
|
|
|
+ deviation = Math.abs(steps - availableSteps[index]);
|
|
|
+ if(minDeviation == null || deviation < minDeviation) {
|
|
|
+ minDeviation = deviation;
|
|
|
+ minDeviationIndex = index;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(minDeviation !== null) {
|
|
|
+ return minDeviationIndex;
|
|
|
+ } else {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ updateStepValue: function(stepValue, updateInputField) {
|
|
|
+ steps = stepValue;
|
|
|
+ materialScreen.uniforms.steps.value = steps;
|
|
|
+ if(updateInputField) {
|
|
|
+ $('#steps').val(stepValue);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ initStepControls: function() {
|
|
|
+ var me = this,
|
|
|
+ stepsInput = $('#steps'),
|
|
|
+ stepsAdjustInput = $('#steps-adjust');
|
|
|
+
|
|
|
+ steps = stepsInput.val();
|
|
|
+ stepsInput.change(function() {
|
|
|
+ steps = stepsInput.val();
|
|
|
+ me.updateStepValue(steps, false);
|
|
|
+ });
|
|
|
+
|
|
|
+ adjustSteps = stepsAdjustInput.is(':checked');
|
|
|
+
|
|
|
+ stepsAdjustInput.change(function() {
|
|
|
+ adjustSteps = $(this).is(':checked');
|
|
|
+ if(adjustSteps) {
|
|
|
+ stepsInput.prop('disabled', true);
|
|
|
+ } else {
|
|
|
+ stepsInput.prop('disabled', false);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+};
|
|
|
+;var TransferHelper = function() {
|
|
|
+ var me = this,
|
|
|
+ changed = false,
|
|
|
+ canvas = document.getElementById('transfer-function'),
|
|
|
+ $canvas = $(canvas),
|
|
|
+ context = canvas.getContext('2d'),
|
|
|
+ hiddenCanvas = document.getElementById('hidden-transfer'),
|
|
|
+ hiddenContext = hiddenCanvas.getContext('2d'),
|
|
|
+ transferSpanHolder = $('#transfer-span-holder'),
|
|
|
+ transfer = $('#transfer'),
|
|
|
+ disabled = true,
|
|
|
+ handles = $('span.transfer'),
|
|
|
+ $standardTf = $('img#standard-tf').get(0),
|
|
|
+ offsetLeft = {
|
|
|
+ blue: 0,
|
|
|
+ turquois: 0.25,
|
|
|
+ green: 0.5,
|
|
|
+ orange: 0.75,
|
|
|
+ red: 1
|
|
|
+ },
|
|
|
+ colorCodes = {
|
|
|
+ blue: '#0000FF',
|
|
|
+ turquois: '#00FFFF',
|
|
|
+ green: '#00FF00',
|
|
|
+ orange: '#FFFF00',
|
|
|
+ red: '#FF0000'
|
|
|
+ },
|
|
|
+ opacities = Array(255);
|
|
|
+
|
|
|
+ for(counter = 0; counter < opacities.length; counter++) {
|
|
|
+ opacities[counter] = 255;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ $('input#toggle-transfer').on('click', function() {
|
|
|
+ if(disabled) {
|
|
|
+ enableTransferFunction();
|
|
|
+ } else {
|
|
|
+ disableTransferFunction();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ var getOffsetLeft = function() {
|
|
|
+ return transfer.offset().left - transfer.parent().offset().left;
|
|
|
+ }
|
|
|
+
|
|
|
+ var removePxOffString = function(str) {
|
|
|
+ return parseInt(str.replace('px', ''));
|
|
|
+ }
|
|
|
+
|
|
|
+ var updateGradient = function() {
|
|
|
+ // Create gradient
|
|
|
+
|
|
|
+ var grd = context.createLinearGradient(0,0,255,0);
|
|
|
+
|
|
|
+ $.each(handles, function(index, value) {
|
|
|
+ var $value = $(value),
|
|
|
+ colorName = $value.attr('color'),
|
|
|
+ colorOffsetLeft = offsetLeft[colorName],
|
|
|
+ colorCode = colorCodes[colorName];
|
|
|
+
|
|
|
+ grd.addColorStop(colorOffsetLeft, colorCode);
|
|
|
+ });
|
|
|
+ // Fill with gradient
|
|
|
+ context.fillStyle = grd;
|
|
|
+ context.fillRect(0,0,255, 10);
|
|
|
+
|
|
|
+ applyOpacities();
|
|
|
+
|
|
|
+ changed = true;
|
|
|
+ };
|
|
|
+
|
|
|
+ var applyOpacities = function() {
|
|
|
+ var imageData = context.getImageData(0, 0, 255, 1),
|
|
|
+ data = imageData.data;
|
|
|
+
|
|
|
+ for(counter = 0; counter < opacities.length; counter++) {
|
|
|
+ data[(counter * 4) + 3] = opacities[counter];
|
|
|
+ }
|
|
|
+
|
|
|
+ hiddenContext.putImageData(imageData, 0, 0, 0, 0, 255, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ var updateHandlePosition = function(element) {
|
|
|
+ var colorLeft = removePxOffString($(element).css('left')) - getOffsetLeft(),
|
|
|
+ colorOffsetLeft = colorLeft / $canvas.width(),
|
|
|
+ colorName = $(element).attr('color');
|
|
|
+
|
|
|
+ if(colorOffsetLeft > 1.0) {
|
|
|
+ colorOffsetLeft = 1.0;
|
|
|
+ }
|
|
|
+ if(colorOffsetLeft < 0.0) {
|
|
|
+ colorOffsetLeft = 0.0;
|
|
|
+ }
|
|
|
+ offsetLeft[colorName] = colorOffsetLeft;
|
|
|
+ updateGradient();
|
|
|
+ };
|
|
|
+
|
|
|
+ var enableTransferFunction = function() {
|
|
|
+ $.each(handles, function(index, value) {
|
|
|
+ var $value = $(value),
|
|
|
+ colorName = $value.attr('color'),
|
|
|
+ colorOffsetLeft = offsetLeft[colorName],
|
|
|
+ colorLeft = getOffsetLeft() + ($canvas.width() * colorOffsetLeft),
|
|
|
+ colorCode = colorCodes[colorName];
|
|
|
+
|
|
|
+ $value.css({left: colorLeft, 'background-color': colorCode });
|
|
|
+ $(value).draggable({
|
|
|
+ containment: '#transfer-span-holder',
|
|
|
+ scroll: false,
|
|
|
+ axis: 'x',
|
|
|
+ cursor: "crosshair",
|
|
|
+ stop: function() {
|
|
|
+ updateHandlePosition(this);
|
|
|
+ },
|
|
|
+ drag: function() {
|
|
|
+ updateHandlePosition(this);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ showHandles();
|
|
|
+ updateGradient();
|
|
|
+ disabled = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ var disableTransferFunction = function() {
|
|
|
+ context.drawImage($standardTf, 0, 0, 255, 10);
|
|
|
+ applyOpacities();
|
|
|
+ hideHandles();
|
|
|
+ disabled = true;
|
|
|
+ changed = true;
|
|
|
+ };
|
|
|
+
|
|
|
+ var showHandles = function() {
|
|
|
+ $.each(handles, function(index, value) {
|
|
|
+ $(value).removeClass('hidden');
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ var hideHandles = function() {
|
|
|
+ $.each(handles, function(index, value) {
|
|
|
+ $(value).addClass('hidden');
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ //canvas.setAttribute('width', $canvas.width());
|
|
|
+ //canvas.setAttribute('height', $canvas.height());
|
|
|
+ disableTransferFunction();
|
|
|
+
|
|
|
+ $(document).on('opacityChanged', function(e, params) {
|
|
|
+ if(params != undefined && params.opacities != undefined) {
|
|
|
+ opacities = params.opacities;
|
|
|
+ applyOpacities();
|
|
|
+ changed = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ transferFunctionChanged : function() {
|
|
|
+ return changed;
|
|
|
+ },
|
|
|
+
|
|
|
+ getCurrentTransferFunction : function() {
|
|
|
+ changed = false;
|
|
|
+ return hiddenContext.getImageData(0, 0, 255, 1);
|
|
|
+ }
|
|
|
+ };
|
|
|
+}
|
|
|
+;var VolumeFace = function(orientation, direction) {
|
|
|
+ this.orientation = orientation;
|
|
|
+ this.direction = direction;
|
|
|
+}
|
|
|
+
|
|
|
+VolumeFace.prototype = {
|
|
|
+ constructor: VolumeFace,
|
|
|
+ orientation: 0,
|
|
|
+ direction: 0,
|
|
|
+
|
|
|
+ getAxisOfNaviation: function() {
|
|
|
+ var axis = {
|
|
|
+ plane: {
|
|
|
+ ver: null,
|
|
|
+ hor: null
|
|
|
+ },
|
|
|
+ slider: null
|
|
|
+ };
|
|
|
+
|
|
|
+ if(this.orientation == VolumeFaceOrientation.XY) {
|
|
|
+ axis.plane.ver = new Orientation(Axis.Y);
|
|
|
+ axis.plane.hor = new Orientation(Axis.X);
|
|
|
+ axis.slider = new Orientation(Axis.Z);
|
|
|
+ } else if(this.orientation == VolumeFaceOrientation.YZ) {
|
|
|
+ axis.plane.ver = new Orientation(Axis.Y);
|
|
|
+ axis.plane.hor = new Orientation(Axis.Z);
|
|
|
+ axis.slider = new Orientation(Axis.X);
|
|
|
+ } else if(this.orientation == VolumeFaceOrientation.XZ) {
|
|
|
+ axis.plane.ver = new Orientation(Axis.Z);
|
|
|
+ axis.plane.hor = new Orientation(Axis.X);
|
|
|
+ axis.slider = new Orientation(Axis.Y);
|
|
|
+ }
|
|
|
+
|
|
|
+ return axis;
|
|
|
+ },
|
|
|
+
|
|
|
+ getIdentifier: function() {
|
|
|
+ return this.orientation + '-' + this.direction;
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+var VolumeFaceOrientation = {
|
|
|
+ XY: 0,
|
|
|
+ XZ: 1,
|
|
|
+ YZ: 2
|
|
|
+}
|
|
|
+
|
|
|
+var VolumeFaceDirection = {
|
|
|
+ FRONT: 0,
|
|
|
+ BACK: 1
|
|
|
+}
|
|
|
+
|
|
|
+function determineVolumeFace(cubeFaceNormal) {
|
|
|
+ var orientation, direction;
|
|
|
+ if(cubeFaceNormal.x != 0) {
|
|
|
+ orientation = VolumeFaceOrientation.YZ;
|
|
|
+ direction = determineFaceOrientation(cubeFaceNormal.x);
|
|
|
+ } else if(cubeFaceNormal.y != 0) {
|
|
|
+ orientation = VolumeFaceOrientation.XZ;
|
|
|
+ direction = determineFaceOrientation(cubeFaceNormal.y);
|
|
|
+ } else if(cubeFaceNormal.z != 0) {
|
|
|
+ orientation = VolumeFaceOrientation.XY;
|
|
|
+ direction = determineFaceOrientation(cubeFaceNormal.z);
|
|
|
+ }
|
|
|
+ return new VolumeFace(orientation, direction);
|
|
|
+}
|
|
|
+
|
|
|
+function determineFaceOrientation(normalComp) {
|
|
|
+ return normalComp > 0 ? VolumeFaceDirection.FRONT : VolumeFaceDirection.BACK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function isFrontFace(orientation, direction) {
|
|
|
+ return orientation == VolumeFaceOrientation.XY
|
|
|
+ && direction == VolumeFaceDirection.FRONT;
|
|
|
+}
|
|
|
+
|
|
|
+function isBackFace(orientation, direction) {
|
|
|
+ return orientation == VolumeFaceOrientation.XY
|
|
|
+ && direction == VolumeFaceDirection.BACK;
|
|
|
+}
|
|
|
+
|
|
|
+function isLeftFace(orientation, direction) {
|
|
|
+ return orientation == VolumeFaceOrientation.YZ
|
|
|
+ && direction == VolumeFaceDirection.FRONT;
|
|
|
+}
|
|
|
+
|
|
|
+function isRightFace(orientation, direction) {
|
|
|
+ return orientation == VolumeFaceOrientation.YZ
|
|
|
+ && direction == VolumeFaceDirection.BACK;
|
|
|
+}
|
|
|
+
|
|
|
+function isTopFace(orientation, direction) {
|
|
|
+ return orientation == VolumeFaceOrientation.XZ
|
|
|
+ && direction == VolumeFaceDirection.FRONT;
|
|
|
+}
|
|
|
+
|
|
|
+function isBottomFace(orientation, direction) {
|
|
|
+ return orientation == VolumeFaceOrientation.XZ
|
|
|
+ && direction == VolumeFaceDirection.BACK;
|
|
|
+}
|
|
|
+;var ZoomHelper = function() {
|
|
|
+ var navigationPlaneHorLabel = $('#navigation-plane-hor-label'),
|
|
|
+ navigationPlaneVerLabel = $('#navigation-plane-ver-label'),
|
|
|
+ navigationSliderLabel = $('#navigation-slider-label'),
|
|
|
+ zoomStatus = $('#zoom-status'),
|
|
|
+ zoomInButton = $('input#zoomin'),
|
|
|
+ zoomOutButton = $('input#zoomout'),
|
|
|
+ navigationPlane = $('div#navigation-plane'),
|
|
|
+ navigationPlaneParent = navigationPlane.parent(),
|
|
|
+ navigationSlider = $('div#navigation-slider'),
|
|
|
+ navigationSliderParent = navigationSlider.parent(),
|
|
|
+ displayTimestamp = null,
|
|
|
+ planeOrientation = {
|
|
|
+ ver: new Orientation(Axis.Y, OffsetTo.LEFT),
|
|
|
+ hor: new Orientation(Axis.X, OffsetTo.TOP),
|
|
|
+ direction: VolumeFaceDirection.BACK,
|
|
|
+ orientation: VolumeFaceOrientation.XY
|
|
|
+ },
|
|
|
+ sliderOrientation = {axis: new Orientation(Axis.Z, OffsetTo.TOP) },
|
|
|
+ zoomedIn,
|
|
|
+ zoomedInfoArray = {
|
|
|
+ dimension: Array(3),
|
|
|
+ offset: Array(3)
|
|
|
+ };
|
|
|
+
|
|
|
+ var lastExecutionTime = Date.now();
|
|
|
+ // adjust navigation related navigations
|
|
|
+ $container.on('animation', function() {
|
|
|
+ determineAxisLabels();
|
|
|
+ determinePlanePosition();
|
|
|
+ determineSliderPosition();
|
|
|
+ });
|
|
|
+
|
|
|
+ // one has to press ctrl AND alt while clicking
|
|
|
+ $container.on('click', 'canvas', function(event){
|
|
|
+ event.stopPropagation();
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ // keyboard shortcut activated or button zoom in pressed before?
|
|
|
+ if((event.ctrlKey == false || event.altKey == false)
|
|
|
+ && !zoomInActivated) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var mouseX = ( (event.clientX - $canvas.offset().left) / ($canvas.width()) ) * 2 - 1,
|
|
|
+ mouseY = - ( (event.clientY - $canvas.offset().top) / ($canvas.height()) ) * 2 + 1;
|
|
|
+
|
|
|
+ var vector = new THREE.Vector3( mouseX, mouseY, camera.near);
|
|
|
+
|
|
|
+ vector = vector.unproject( camera );
|
|
|
+
|
|
|
+ var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
|
|
|
+
|
|
|
+ var intersects = raycaster.intersectObjects( [frontBox] );
|
|
|
+
|
|
|
+ if(intersects.length > 0) {
|
|
|
+ if(!handleZoomStatus(true)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ var intersect = intersects[0],
|
|
|
+ point = intersect.point;
|
|
|
+
|
|
|
+ var geometry = new THREE.BoxGeometry( 0.1, 0.1, 0.1 );
|
|
|
+
|
|
|
+ var material = new THREE.MeshBasicMaterial( {
|
|
|
+ color: new THREE.Color( 0xaaaaaa ),
|
|
|
+ opacity: 0.3
|
|
|
+ });
|
|
|
+
|
|
|
+ mesh = new THREE.Mesh( geometry, material );
|
|
|
+ mesh.position.x = point.x;
|
|
|
+ mesh.position.y = point.y;
|
|
|
+ mesh.position.z = point.z;
|
|
|
+ scene.add(mesh);
|
|
|
+ intersectCubes[intersectCubes.length] = mesh;
|
|
|
+ intersectCubesTimeStamps[intersectCubesTimeStamps.length] = Date.now();
|
|
|
+
|
|
|
+ var realPoint = point.clone();
|
|
|
+ zoomIn(point);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ function zoomIn(realPoint, alreadyTranslated) {
|
|
|
+ if(alreadyTranslated == undefined || !alreadyTranslated) {
|
|
|
+ // retranslate the point into original position beginning from 0,0,0
|
|
|
+ realPoint.add(new THREE.Vector3(0.5, 0.5, 0.5));
|
|
|
+ }
|
|
|
+
|
|
|
+ volumePointArray = realPoint.toArray();
|
|
|
+
|
|
|
+ var processingUrl = homeUrl + 'volumes/' + volumeId + '/processing/sub/';
|
|
|
+ $.each(volumePointArray, function(index, value) {
|
|
|
+ dimWidth = null;
|
|
|
+ if(index == 0) {
|
|
|
+ dimWidth = textureInfo.originalSize.sizex;
|
|
|
+ } else if(index == 1) {
|
|
|
+ dimWidth = textureInfo.originalSize.sizey;
|
|
|
+ } else {
|
|
|
+ dimWidth = textureInfo.originalSize.sizez;
|
|
|
+ }
|
|
|
+ value *= dimWidth;
|
|
|
+ // due to interpolation algorithm, we had to rotate the whole cube, that it matches
|
|
|
+ // the display of imagej
|
|
|
+ // so we have to map the current pointer values to the real volume values
|
|
|
+ // but only for the y and z direction --> the x direction is all right
|
|
|
+ if(index > 0) {
|
|
|
+ value = dimWidth - value;
|
|
|
+ }
|
|
|
+
|
|
|
+ value = Math.floor(value);
|
|
|
+ volumePointArray[index] = value;
|
|
|
+ processingUrl += value + '/';
|
|
|
+ });
|
|
|
+
|
|
|
+ frameNumber = imgInfo.frameFrom + currentTexture;
|
|
|
+
|
|
|
+ processingUrl += frameNumber + '/';
|
|
|
+
|
|
|
+ $.ajax({
|
|
|
+ url: processingUrl,
|
|
|
+ success: function(data) {
|
|
|
+ var available = false;
|
|
|
+ var availableTestCounter = 0;
|
|
|
+ zoomedInfo = data;
|
|
|
+
|
|
|
+ // this function is called recursive by the settimeout statement
|
|
|
+ availableTest = function() {
|
|
|
+ $.ajax({
|
|
|
+ url: homeUrl + 'volumes/' + volumeId + '/processing/sprite/' + zoomedInfo.spriteId + '/available/',
|
|
|
+ success: function(data) {
|
|
|
+ available = data.available;
|
|
|
+ },
|
|
|
+ dataType: 'json',
|
|
|
+ async: false
|
|
|
+ });
|
|
|
+
|
|
|
+ if(available) {
|
|
|
+ // subvolume available: fetch it
|
|
|
+ fetchZoomedVolume();
|
|
|
+ } else if(availableTestCounter < 20) {
|
|
|
+ // abort condition not reached --> try again
|
|
|
+ setTimeout(availableTest, 2000);
|
|
|
+ availableTestCounter++;
|
|
|
+ } else {
|
|
|
+ // abort condition reached --> error handling
|
|
|
+ $(document).trigger('zoomActionFinished', { zoomAction: 'zoomOut', error: true });
|
|
|
+ }
|
|
|
+ };
|
|
|
+ setTimeout(availableTest, 2000);
|
|
|
+ },
|
|
|
+ dataType: 'json',
|
|
|
+ async: true,
|
|
|
+ error: function(data) {
|
|
|
+ helper.displayMessage('Sorry, an error occured during processing zoom', true, null, 2500);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ var fetchZoomedVolume = function() {
|
|
|
+ imageSrc = homeUrl + 'volumes/' + volumeId + '/processing/sprite/' + zoomedInfo.spriteId + '/show/';
|
|
|
+
|
|
|
+ var image = new Image();
|
|
|
+ var texture = initTexture(new THREE.Texture(image));
|
|
|
+
|
|
|
+ image.onload = function() {
|
|
|
+
|
|
|
+ materialScreen.uniforms.numberOfSlices.value = zoomedInfo.numberOfSlices;
|
|
|
+ materialScreen.uniforms.numberOfSlices.needsupdate = true;
|
|
|
+ materialScreen.uniforms.slicesOverX.value = zoomedInfo.slicesOverX;
|
|
|
+ materialScreen.uniforms.slicesOverX.needsUpdate = true;
|
|
|
+ materialScreen.uniforms.slicesOverY.value = zoomedInfo.slicesOverY;
|
|
|
+ materialScreen.uniforms.slicesOverY.needsUpdate = true;
|
|
|
+ materialScreen.uniforms.numberOfSprites.value = 1;
|
|
|
+ materialScreen.uniforms.numberOfSprites.needsUpdate = true;
|
|
|
+ materialScreen.uniforms.slicesPerSprite.value = zoomedInfo.numberOfSlices;
|
|
|
+ materialScreen.uniforms.slicesPerSprite.needsUpdate = true;
|
|
|
+
|
|
|
+ updateTexture([texture]);
|
|
|
+
|
|
|
+ zoomedVolumeDimension.xmin = zoomedInfo.dimension.xmin;
|
|
|
+ zoomedVolumeDimension.xmax = zoomedInfo.dimension.xmin + zoomedInfo.dimension.xywidth - 1;
|
|
|
+ zoomedVolumeDimension.ymin = zoomedInfo.dimension.ymin;
|
|
|
+ zoomedVolumeDimension.ymax = zoomedInfo.dimension.ymin + zoomedInfo.dimension.xywidth - 1;
|
|
|
+ zoomedVolumeDimension.zmin = zoomedInfo.dimension.zmin;
|
|
|
+ zoomedVolumeDimension.zmax = zoomedInfo.dimension.zmin + zoomedInfo.numberOfSlices - 1;
|
|
|
+
|
|
|
+ originalVolumeDimension = currentVolumeDimension;
|
|
|
+ originalDimension = currentDimension;
|
|
|
+
|
|
|
+ currentVolumeDimension = zoomedVolumeDimension;
|
|
|
+
|
|
|
+ repositionLayerSliders();
|
|
|
+
|
|
|
+ $(document).trigger('zoomActionFinished', { zoomAction: 'zoomIn', textureNumber: frameNumber });
|
|
|
+ }
|
|
|
+
|
|
|
+ image.src = imageSrc;
|
|
|
+ };
|
|
|
+
|
|
|
+ $container.on('contextmenu', function(event){
|
|
|
+ if(event.ctrlKey == false) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(event.altKey == false) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!handleZoomStatus(false)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return zoomOut();
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ function zoomOut() {
|
|
|
+ materialScreen.uniforms.numberOfSlices.value = textureInfo.info.numberOfSlices;
|
|
|
+ materialScreen.uniforms.numberOfSlices.needsupdate = true;
|
|
|
+ materialScreen.uniforms.slicesOverX.value = textureInfo.info.slicesOverX;
|
|
|
+ materialScreen.uniforms.slicesOverX.needsUpdate = true;
|
|
|
+ materialScreen.uniforms.slicesOverY.value = textureInfo.info.slicesOverY;
|
|
|
+ materialScreen.uniforms.slicesOverY.needsUpdate = true;
|
|
|
+ materialScreen.uniforms.numberOfSprites.value = imgInfo.numberOfSprites;
|
|
|
+ materialScreen.uniforms.numberOfSprites.needsUpdate = true;
|
|
|
+ materialScreen.uniforms.slicesPerSprite.value = imgInfo.slicesPerSprite;
|
|
|
+ materialScreen.uniforms.slicesPerSprite.needsUpdate = true;
|
|
|
+
|
|
|
+ updateTexture();
|
|
|
+
|
|
|
+ currentVolumeDimension = originalVolumeDimension;
|
|
|
+ currentDimension = originalDimension;
|
|
|
+
|
|
|
+ repositionLayerSliders();
|
|
|
+
|
|
|
+ $(document).trigger('zoomActionFinished', { zoomAction: 'zoomOut' });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * return: procceed or not
|
|
|
+ */
|
|
|
+ function handleZoomStatus(zoomIn) {
|
|
|
+ zoomInButton.removeClass('red');
|
|
|
+ zoomInActivated = false;
|
|
|
+
|
|
|
+ if(zoomIn && zoomedIn) {
|
|
|
+ return false;
|
|
|
+ } else if(!zoomIn && !zoomedIn) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ waitDiv.removeClass('hidden');
|
|
|
+
|
|
|
+ if(zoomIn) {
|
|
|
+ zoomInButton.prop('disabled', true);
|
|
|
+ } else {
|
|
|
+ zoomInButton.prop('disabled', false);
|
|
|
+ }
|
|
|
+
|
|
|
+ displayMessage = zoomIn ? 'Generating zoomed subvolume, please wait a moment' : 'Zooming out';
|
|
|
+ helper.displayMessage(displayMessage);
|
|
|
+ displayTimestamp = Date.now();
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // general function to disable stuff like messages etc.
|
|
|
+ $(document).on('zoomActionFinished', function(e, params) {
|
|
|
+ zoomedIn = params.zoomAction == 'zoomIn';
|
|
|
+
|
|
|
+ timeout = 2000 - (Date.now() - displayTimestamp);
|
|
|
+ if(timeout < 0) {
|
|
|
+ timeout = 0;
|
|
|
+ }
|
|
|
+ helper.fadeoutMessage(null, timeout);
|
|
|
+
|
|
|
+ zoomedStatusText = '';
|
|
|
+ if(zoomedIn) {
|
|
|
+ zoomStatus.addClass('green-background');
|
|
|
+ zoomedStatusText = 'zoomed in';
|
|
|
+
|
|
|
+ $.each($('.res-link'), function(index, value) {
|
|
|
+ $(value).addClass('disabled');
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ zoomStatus.removeClass('green-background');
|
|
|
+ zoomedStatusText = 'zoomed out';
|
|
|
+ console.log(params);
|
|
|
+ if(params.error) {
|
|
|
+ console.log('error handling');
|
|
|
+ errorMessage = 'Error during subvolume generation - zoomed out again';
|
|
|
+ helper.displayMessage(errorMessage, true, null, 5000);
|
|
|
+ }
|
|
|
+
|
|
|
+ $.each($('.res-link'), function(index, value) {
|
|
|
+ $(value).removeClass('disabled');
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ zoomStatus.html(zoomedStatusText);
|
|
|
+ waitDiv.addClass('hidden');
|
|
|
+ });
|
|
|
+
|
|
|
+ // draggable related stuff
|
|
|
+ $(document).on('zoomActionFinished', function(e, params) {
|
|
|
+
|
|
|
+ zoomedIn = params.zoomAction == 'zoomIn';
|
|
|
+
|
|
|
+ if(zoomedIn) {
|
|
|
+ zoomedInfoArray.offset[Axis.X] = zoomedVolumeDimension.xmin;
|
|
|
+ zoomedInfoArray.offset[Axis.Y] = zoomedVolumeDimension.ymin;
|
|
|
+ zoomedInfoArray.offset[Axis.Z] = zoomedVolumeDimension.zmin;
|
|
|
+
|
|
|
+ zoomedInfoArray.dimension[Axis.X] = zoomedInfo.dimension.xywidth;
|
|
|
+ zoomedInfoArray.dimension[Axis.Y] = zoomedInfo.dimension.xywidth;
|
|
|
+ zoomedInfoArray.dimension[Axis.Z] = zoomedInfo.numberOfSlices;
|
|
|
+ } else {
|
|
|
+ navigationPlane.hide();
|
|
|
+ navigationPlaneParent.removeClass('white');
|
|
|
+
|
|
|
+ navigationSlider.hide();
|
|
|
+ navigationSliderParent.removeClass('white');
|
|
|
+ }
|
|
|
+
|
|
|
+ navigationPlane.removeClass('no-pos-set');
|
|
|
+ navigationSlider.removeClass('no-pos-set');
|
|
|
+ });
|
|
|
+
|
|
|
+ navigationPlane.draggable({
|
|
|
+ containment: '#navigation-plane-container',
|
|
|
+ scroll: false,
|
|
|
+ stop: function() {
|
|
|
+ zoomedDraggableChanged();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ navigationSlider.draggable({
|
|
|
+ containment: '#navigation-slider-container',
|
|
|
+ scroll: false,
|
|
|
+ stop: function() {
|
|
|
+ zoomedDraggableChanged();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ function zoomedDraggableChanged() {
|
|
|
+ waitDiv.removeClass('hidden');
|
|
|
+ var planeWidthHalf = navigationPlane.width() / 2,
|
|
|
+ planeHeightHalf = navigationPlane.height() / 2,
|
|
|
+ planeOffsetLeft = navigationPlane.offset().left - navigationPlaneParent.offset().left - 1,
|
|
|
+ planeOffsetTop = navigationPlane.offset().top - navigationPlaneParent.offset().top - 1,
|
|
|
+
|
|
|
+ sliderHeightHalf = navigationSlider.height() / 2,
|
|
|
+ sliderOffsetTop = navigationSlider.offset().top - navigationSliderParent.offset().top - 1,
|
|
|
+ orientation = planeOrientation.orientation,
|
|
|
+ direction = planeOrientation.direction;
|
|
|
+
|
|
|
+
|
|
|
+ // set correct border values due to messure errors
|
|
|
+ if(planeOffsetLeft < 0) {
|
|
|
+ planeOffsetLeft = 0;
|
|
|
+ } else if(planeOffsetLeft > navigationPlaneParent.width() - navigationPlane.width()) {
|
|
|
+ planeOffsetLeft = navigationPlaneParent.width() - navigationPlane.width();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(planeOffsetTop < 0) {
|
|
|
+ planeOffsetTop = 0;
|
|
|
+ } else if(planeOffsetTop > navigationPlaneParent.height() - navigationPlane.height()) {
|
|
|
+ planeOffsetTop = navigationPlaneParent.height() - navigationPlane.height();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(sliderOffsetTop < 0) {
|
|
|
+ sliderOffsetTop = 0;
|
|
|
+ } else if(sliderOffsetTop > navigationSliderParent.height() - navigationSlider.height()) {
|
|
|
+ sliderOffsetTop = navigationSliderParent.height() - navigationSlider.height();
|
|
|
+ }
|
|
|
+
|
|
|
+ planeOffsetLeft = planeOffsetLeft + planeWidthHalf;
|
|
|
+ planeOffsetTop = planeOffsetTop + planeHeightHalf;
|
|
|
+ sliderOffsetTop = sliderOffsetTop + sliderHeightHalf;
|
|
|
+
|
|
|
+ horAxis = planeOrientation.hor.axis;
|
|
|
+ verAxis = planeOrientation.ver.axis;
|
|
|
+ console.log('orientation ', planeOrientation.orientation);
|
|
|
+ console.log('direction ', planeOrientation.direction);
|
|
|
+ pointAsArray = Array(3);
|
|
|
+
|
|
|
+ pointAsArray[horAxis] = planeOffsetLeft / navigationPlaneParent.width();
|
|
|
+ pointAsArray[verAxis] = 1.0 - (planeOffsetTop / navigationPlaneParent.height());
|
|
|
+
|
|
|
+ if(planeOrientation.direction == VolumeFaceDirection.BACK) {
|
|
|
+ pointAsArray[horAxis] = 1.0 - pointAsArray[horAxis];
|
|
|
+ } else if(planeOrientation.orientation == VolumeFaceOrientation.XZ) {
|
|
|
+ pointAsArray[horAxis] = 1.0 - pointAsArray[horAxis];
|
|
|
+ }
|
|
|
+
|
|
|
+ pointAsArray[sliderOrientation.axis] = 1.0 - (sliderOffsetTop / navigationSliderParent.height());
|
|
|
+
|
|
|
+ if((sliderOrientation.axis == Axis.Z
|
|
|
+ && planeOrientation.direction == VolumeFaceDirection.FRONT)
|
|
|
+ || (sliderOrientation.axis == Axis.Y
|
|
|
+ && planeOrientation.direction == VolumeFaceDirection.FRONT)
|
|
|
+ || (sliderOrientation.axis == Axis.X
|
|
|
+ && planeOrientation.direction == VolumeFaceDirection.BACK)) {
|
|
|
+
|
|
|
+ pointAsArray[sliderOrientation.axis] = 1.0 - pointAsArray[sliderOrientation.axis];
|
|
|
+ }
|
|
|
+
|
|
|
+ point = new THREE.Vector3(pointAsArray[0], pointAsArray[1], pointAsArray[2]);
|
|
|
+
|
|
|
+ zoomIn(point, true);
|
|
|
+ };
|
|
|
+
|
|
|
+ var zoomInActivated = false;
|
|
|
+ zoomInButton.on('click', function() {
|
|
|
+ zoomInActivated = !zoomInActivated;
|
|
|
+
|
|
|
+ if(zoomInActivated) {
|
|
|
+ $(this).addClass('red');
|
|
|
+ } else {
|
|
|
+ $(this).removeClass('red');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ zoomOutButton.on('click', function() {
|
|
|
+ zoomInButton.removeClass('red');
|
|
|
+
|
|
|
+ if(!handleZoomStatus(false)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return zoomOut();
|
|
|
+ });
|
|
|
+
|
|
|
+ function determineAxisLabels() {
|
|
|
+ if(Date.now() - lastExecutionTime > 100) {
|
|
|
+ var lookAtVector = new THREE.Vector3(0,0, -1);
|
|
|
+ lookAtVector.applyQuaternion(camera.quaternion);
|
|
|
+
|
|
|
+ xIterator = -0.4;
|
|
|
+ yIterator = -0.4;
|
|
|
+ facesIntersect = {};
|
|
|
+ interSectStartingPoint = new THREE.Vector3(xIterator, yIterator, camera.near);
|
|
|
+ for(xIterator = -0.4; xIterator <= 0.4; xIterator += 0.2) {
|
|
|
+ for(yIterator = -0.4; yIterator <= 0.4; yIterator += 0.2) {
|
|
|
+ interSectStartingPoint.x = xIterator;
|
|
|
+ interSectStartingPoint.y = yIterator;
|
|
|
+
|
|
|
+
|
|
|
+ vector = interSectStartingPoint.unproject( camera );
|
|
|
+
|
|
|
+ var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
|
|
|
+
|
|
|
+ var intersects = raycaster.intersectObjects( [frontBox] );
|
|
|
+
|
|
|
+ if(intersects.length > 0) {
|
|
|
+ var intersect = intersects[0],
|
|
|
+ point = intersect.point,
|
|
|
+ face = intersect.face,
|
|
|
+ faceObject = determineVolumeFace(face.normal),
|
|
|
+ faceIdent = faceObject.getIdentifier();
|
|
|
+ alreadyAdded = Object.keys(facesIntersect).indexOf(faceIdent) >= 0;
|
|
|
+
|
|
|
+ if(alreadyAdded) {
|
|
|
+ facesIntersect[faceIdent].count++;
|
|
|
+ } else {
|
|
|
+ facesIntersect[faceIdent] = { faceObject: faceObject, count: 1};
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ frontFace = { count: 0 };
|
|
|
+ for(faceIdent in facesIntersect) {
|
|
|
+ if(facesIntersect[faceIdent].count > frontFace.count) {
|
|
|
+ frontFace = facesIntersect[faceIdent];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(frontFace.faceObject != undefined) {
|
|
|
+ volumeFace = frontFace.faceObject;
|
|
|
+
|
|
|
+ if(volumeFace.orientation == VolumeFaceOrientation.XZ) {
|
|
|
+ //console.log(volumeFace.direction, lookAtVector);
|
|
|
+ //console.log(lookAtVector.x < 0.015, lookAtVector.z < 0.015);
|
|
|
+ }
|
|
|
+
|
|
|
+ axisOfNaviation = volumeFace.getAxisOfNaviation();
|
|
|
+
|
|
|
+ planeOrientation = axisOfNaviation.plane;
|
|
|
+ planeOrientation.hor.offsetTo = OffsetTo.LEFT;
|
|
|
+ planeOrientation.ver.offsetTo = OffsetTo.TOP;
|
|
|
+ planeOrientation.direction = volumeFace.direction;
|
|
|
+ planeOrientation.orientation = volumeFace.orientation;
|
|
|
+
|
|
|
+ sliderOrientation = axisOfNaviation.slider;
|
|
|
+ sliderOrientation.offsetTo = OffsetTo.TOP;
|
|
|
+
|
|
|
+ navigationPlaneHorLabel.html(planeOrientation.hor.getLabel());
|
|
|
+ navigationPlaneVerLabel.html(planeOrientation.ver.getLabel());
|
|
|
+ navigationSliderLabel.html(sliderOrientation.getLabel());
|
|
|
+ }
|
|
|
+
|
|
|
+ lastExecutionTime = Date.now();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function determinePlanePosition() {
|
|
|
+ if(!zoomedIn) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(navigationPlane.hasClass('ui-draggable-dragging')
|
|
|
+ || navigationPlane.hasClass('no-pos-set')) {
|
|
|
+ navigationPlane.addClass('no-pos-set');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ horAxis = planeOrientation.hor.axis;
|
|
|
+ verAxis = planeOrientation.ver.axis;
|
|
|
+
|
|
|
+ planeRelativeX = navigationPlaneParent.width() / originalSizeArray[horAxis];
|
|
|
+ planeRelativeY = navigationPlaneParent.height() / originalSizeArray[verAxis];
|
|
|
+
|
|
|
+ planeWidth = planeRelativeX * zoomedInfoArray.dimension[horAxis];
|
|
|
+ planeHeight = planeRelativeY * zoomedInfoArray.dimension[verAxis];
|
|
|
+
|
|
|
+ planeWidth = Math.ceil(planeWidth);
|
|
|
+ planeHeight = Math.ceil(planeHeight);
|
|
|
+
|
|
|
+ planeOffsetLeft = zoomedInfoArray.offset[horAxis] * planeRelativeX;
|
|
|
+ if((planeOrientation.direction == VolumeFaceDirection.BACK
|
|
|
+ && planeOrientation.orientation == VolumeFaceOrientation.XY)
|
|
|
+ || (planeOrientation.direction == VolumeFaceDirection.FRONT
|
|
|
+ && planeOrientation.orientation == VolumeFaceOrientation.YZ)) {
|
|
|
+
|
|
|
+ planeOffsetLeft = navigationPlaneParent.width() - (planeOffsetLeft + navigationPlane.width());
|
|
|
+ }
|
|
|
+
|
|
|
+ planeOffsetTop = zoomedInfoArray.offset[verAxis] * planeRelativeY;
|
|
|
+
|
|
|
+
|
|
|
+ navigationPlane.css({
|
|
|
+ 'top': planeOffsetTop + 'px',
|
|
|
+ 'left' : planeOffsetLeft + 'px',
|
|
|
+ 'width': planeWidth + 'px',
|
|
|
+ 'height': planeHeight + 'px'
|
|
|
+ });
|
|
|
+
|
|
|
+ navigationPlane.show();
|
|
|
+ navigationPlaneParent.addClass('white');
|
|
|
+ }
|
|
|
+
|
|
|
+ function determineSliderPosition() {
|
|
|
+ if(!zoomedIn) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(navigationSlider.hasClass('ui-draggable-dragging')
|
|
|
+ || navigationSlider.hasClass('no-pos-set')) {
|
|
|
+ navigationSlider.addClass('no-pos-set');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ sliderRelative = navigationSliderParent.height() / originalSizeArray[sliderOrientation.axis];
|
|
|
+ sliderOffsetTop = zoomedInfoArray.offset[sliderOrientation.axis] * sliderRelative;
|
|
|
+
|
|
|
+ sliderHeight = Math.ceil(sliderRelative * zoomedInfoArray.dimension[sliderOrientation.axis]);
|
|
|
+
|
|
|
+ if(planeOrientation.direction == VolumeFaceDirection.FRONT) {
|
|
|
+ sliderOffsetTop = navigationSliderParent.height() - (navigationSlider.height() + sliderOffsetTop);
|
|
|
+ }
|
|
|
+
|
|
|
+ navigationSlider.css({
|
|
|
+ 'top': sliderOffsetTop + 'px',
|
|
|
+ 'height': sliderHeight + 'px'
|
|
|
+ });
|
|
|
+
|
|
|
+ navigationSlider.show();
|
|
|
+ navigationSliderParent.addClass('white');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+//$(document).on('basicsReady', function() {
|
|
|
+// var zoomHelper = new ZoomHelper();
|
|
|
+//});
|
|
|
+
|
|
|
+function radToDeg(rad) {
|
|
|
+ return rad * 180 / Math.PI;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+;var Orientation = function(axis, offsetTo) {
|
|
|
+ this._axis = axis;
|
|
|
+ this._offsetTo = null;
|
|
|
+}
|
|
|
+
|
|
|
+Orientation.prototype = {
|
|
|
+ constructor: Orientation,
|
|
|
+
|
|
|
+ getLabel: function() {
|
|
|
+ switch(this._axis) {
|
|
|
+ case(Axis.X):
|
|
|
+ return 'x-axis';
|
|
|
+ case(Axis.Y):
|
|
|
+ return 'y-axis';
|
|
|
+ case(Axis.Z):
|
|
|
+ return 'z-axis';
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ get axis() {
|
|
|
+ return this._axis;
|
|
|
+ },
|
|
|
+
|
|
|
+ get offsetTo() {
|
|
|
+ return this._offsetTo;
|
|
|
+ },
|
|
|
+
|
|
|
+ set offsetTo(value) {
|
|
|
+ this._offsetTo = value;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+var Axis = {
|
|
|
+ X: 0,
|
|
|
+ Y: 1,
|
|
|
+ Z: 2
|
|
|
+}
|
|
|
+
|
|
|
+var OffsetTo = {
|
|
|
+ TOP: 0,
|
|
|
+ LEFT: 1,
|
|
|
+ BOTTOM: 2,
|
|
|
+ RIGHT: 3
|
|
|
+}
|
|
|
+;IPE.interceptors.SendInterceptor = (function() {
|
|
|
+ return {
|
|
|
+ init: function() {
|
|
|
+ $(document).ajaxSend(function (e, xhr, settings) {
|
|
|
+ if(settings.url.indexOf('/static/') === -1) {
|
|
|
+ if(!settings.url.endsWith('/')) {
|
|
|
+ settings.url += '/';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+}())
|
|
|
+;var NavigationPlane = function(element, horizontalLabel, verticalLabel) {
|
|
|
+ this._element = element;
|
|
|
+ this._parent = element.parent();
|
|
|
+ this._horizontalLabel = horizontalLabel;
|
|
|
+ this._verticalLabel = verticalLabel;
|
|
|
+
|
|
|
+ this._zoomedInfoArray = null;
|
|
|
+ this._volumeFace = null;
|
|
|
+}
|
|
|
+
|
|
|
+NavigationPlane.prototype = {
|
|
|
+ constructor: NavigationPlane,
|
|
|
+
|
|
|
+ set zoomedInfoArray(value) {
|
|
|
+ this._zoomedInfoArray = value;
|
|
|
+ },
|
|
|
+
|
|
|
+ set volumeFace(value) {
|
|
|
+ this._volumeFace = value;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+;
|