front_idill/src/mosaic/js/zoomInteractions.js
author bastiena
Mon, 27 Aug 2012 14:40:10 +0200
changeset 83 6070a596014e
parent 79 9eff85166868
child 89 b6a115568b52
permissions -rw-r--r--
Documentation for tablets updated reload if no user reenabled

/*
* This file is part of the TraKERS\Front IDILL package.
*
* (c) IRI <http://www.iri.centrepompidou.fr/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/*
 * Projet : TraKERS
 * Module : Front IDILL
 * Fichier : zoomInteractions.js
 * 
 * Auteur : alexandre.bastien@iri.centrepompidou.fr
 * 
 * Fonctionnalités : Définit les fonctions de zoom/dezoom prezoom/preunzoom.
 */

/*
 * Zoom sur la position d'une image, 1ère partie. Durant le laps de temps de time ms, l'utilisateur a le choix de zoomer sur une autre image.
 * Après ce laps de temps, l'image zoom complétement et il n'est plus possible de sélectionner une autre image par pointage.
 * Est appelé dans le fichier :
 * pointers > fonction pointersMosaicInteractions.
 */
Mosaic.prototype.preZoom = function(snapshot)
{
    if(this.currentMode == "NO-USER" || this.currentMode.indexOf("INCOMING") > -1 || snapshot == null || this.helpDisplayed || this.isMosaicFiltering || this.isSearchByCurvesOn || this.gestureDelRequested)
    {
        return;
    }
    
    if(this.fullscreen)
    {
        return;
    }
	this.isPrezooming = true;
    this.preUnzoom();
    //On enlève les notifications initiales si elles existent.
    this.removeNotifications();
    
    //Mosaïque.
    var _this = this;
    //Dimensions de la mosaïque.
    var h = this.height, w = this.width;
    //Longueur en images, nombre d'images et taille de bordure de la mosaïque.
    var len = this.config.imagesByLine, imgs = this.config.imagesToShow, margin = this.marginWidth;
    //Dimensions et position d'un snapshot dans la mosaïque.
    var snHeight = this.snapshotHeight, snWidth = this.snapshotWidth;
    var sTop = snapshot.position().top, sLeft = snapshot.position().left;
    var prezoomPercentage = this.config.prezoomPercentage;
    
    //ID de l'image actuelle.
    var currentId = $('img', snapshot).attr('id');
    
    //Si un zoom est déjà en cours, on ne zoom sur rien d'autre en attendant que ce snapshot ai dézoomé en cas de mouseleave.
    if(this.zoomed)
    {
        this.preUnzoom();
    }
    
    //On indique qu'on a zoomé et on spécifie le snapshot sur lequel on a zoomé.
    this.zoomed = true;
    this.previousZoomedSN = snapshot;
    this.previousId = currentId;
    
    //On récupère les attributs de l'image.
    var fakeImg = $('img', snapshot);
    //On forme la balise de la fausse image et on passe son url pour les grands snapshots.
    fakeImg = '<img id="fake-' + currentId + '" class="snapshots" src="' + fakeImg.attr('src').replace('-little/', '/') + '" />';
    //On génère un faux snapshot identique au précédent et qu'on va coller dessus.
    var fakeSnapshot = '<div id="prezoomContainer-' + currentId + '" class="prezoomContainers"><div id="prezoomSnapshot-' + currentId + '" class="snapshotDivs">' + fakeImg + '</div></div>';
    
    //On l'ajoute à la mosaïque.
    $('#mainPanel').append(fakeSnapshot);
    //On modifie ses attributs.
    // console.log('cid : ' + currentId, $('#fake-' + currentId).length);
    $('#fake-' + currentId).load(function()
    {
    // snapshot.fadeTo(400, '0.5').delay(200).fadeTo(400, '1');
        $('#prezoomContainer-' + currentId).css('top', sTop).css('left', sLeft).css('width', (snWidth + margin)).css('height', (snHeight + margin));
        $('#prezoomSnapshot-' + currentId).css('width', (snWidth)).css('height', (snHeight));
        $('#prezoomContainer-' + currentId).css('display', 'block');
        
        //Dimensions et coordonnées initiales du div sur lequel on zoom.
        var initialDivWidth = $('#prezoomContainer-' + currentId).width(), initialDivHeight = $('#prezoomContainer-' + currentId).height();
        var initialDivTop = $('#prezoomContainer-' + currentId).position().top, initialDivLeft = $('#prezoomContainer-' + currentId).position().left;
        //Dimensions et coordonnées finales du div.
        var finalDivWidth = initialDivWidth * (prezoomPercentage+1), diffWidth = finalDivWidth - initialDivWidth, finalDivHeight = initialDivHeight + diffWidth;
        var finalDivTop = (initialDivTop - (finalDivHeight - snHeight)/2), finalDivLeft = (initialDivLeft - (finalDivWidth - snWidth)/2);
        
        //CAS PARTICULIER pour la position du snapshot zoomé : les bordures.
        if(finalDivTop < 0)
        {
            finalDivTop = -margin;
        }
        if(finalDivTop + finalDivHeight > h)
        {
            finalDivTop = h - finalDivHeight;
        }
        if(finalDivLeft < 0)
        {
            finalDivLeft = 0;
        }
        if(finalDivLeft + finalDivWidth + margin*2 > w)
        {
            finalDivLeft = w - finalDivWidth - margin*2;
        }
        
        //On prézoom le div en le centrant sur le milieu du snapshot pointé.
        $('#prezoomSnapshot-' + currentId).animate(
        {
            width: finalDivWidth + margin,
            height: finalDivHeight - margin*2,
            top: finalDivTop + margin,
            left: finalDivLeft + margin
        }, _this.config.timePrezoom);
        $('#prezoomContainer-' + currentId).animate(
        {
            width: finalDivWidth + margin*2,
            height: finalDivHeight - margin,
            top: finalDivTop + margin,
            left: finalDivLeft
        }, _this.config.timePrezoom, function()
        {
			//On a fini de prézoomer.
			_this.isPrezooming = false;
            //Si on est en mode Kinect.
            if(!_this.config.mouseInteractions)
            {
                //On met le spinner gif sur le pointeur, s'il n'existe pas déjà.
                if($('#spinner').length == 0)
                {
                    //On repère le pointeur ayant provoqué le prezoom.
                    var prezoomPointer;
                    if(!_this.isMainPointerDisplayed)
                    {
                        prezoomPointer = $('#secondPointer');
                    }
                    if(!_this.isSecondPointerDisplayed)
                    {
                        prezoomPointer = $('#mainPointer');
                    }
                    
                    //On crée le spinner s'il y a un pointeur qui indique le temps restant avant le zoom.
					if(prezoomPointer != null && prezoomPointer.length > 0)
					{
						var spinner = "<img id='spinner'></div>";
						$('body').append(spinner);
						$('#spinner').css(
						{
							position: 'absolute',
							top: prezoomPointer.position().top,
							left: prezoomPointer.position().left,
							width: 85,
							height: 85,
							'z-index': 600
						});
						$('#spinner').attr('src', './img/cursors/selector_anim_2.gif');
					}
                }
            }
            //Si on est en mode d'interaction souris, on indique juste qu'on est en prezoom.
            else
            {
                _this.isOnAPrezoomSN = true;
            }
            
            //Si on est en mode mosaic, on indique juste qu'on effectue une selection.
            if(_this.currentMode == 'MOSAIC')
            {
                _this.removeNotifications();
                _this.mosaicSelection();
            }
            //Si on est en filtrage, mais qu'on n'a pas encore de gesture de filtrage, on indique qu'on est en filtrage et en selection.
            else if(_this.currentMode == 'FILTER' && !_this.filterSearchedType && _this.curvesGesturesFound)
            {
                _this.removeNotifications();
                _this.filterSearchAndSelection();
            }
            //Si on est en filtrage avec une gesture de recherche, on indique la gesture et la selection.
            else if(_this.currentMode == 'FILTER' && _this.filterSearchedType)
            {
                _this.removeNotifications();
                _this.filterGestureAndSelection(_this.filterSearchedType, 'valid');
            }
        });
    });
    
    //Si on est en mode Kinect, on zoom après un certain temps.
    if(!this.config.mouseInteractions)
    {
        this.zoomTimeout = setTimeout(function()
        {
            _this.zoom();
        }, this.config.timeoutZoom);
    }
}

/*
 * Dézoome sur la position de l'image. Il est à noter que ce dézoome diffère du dézoom global dans la mesure où celui-ci ne concerne que l'image sur laquelle on a zoomé.
 * Est appelé dans les fichiers :
 * pointers > fonction pointersMosaicInteractions.
 * zoomInteractions > fonctions preZoom et zoom.
 * mosaic > fonction onMouseMove.
 * client > fonction processMsg.
 */
Mosaic.prototype.preUnzoom = function()
{
    $('#spinner').remove();
    
    var _this = this;
    
    //On indique qu'on n'est plus en prezoom.
    this.isOnAPrezoomSN = false;
    clearTimeout(this.zoomTimeout);
    
    //Si on est en mode mosaic, on indique qu'on peut pointer ou bien rechercher.
    if(this.currentMode == 'MOSAIC')
    {
        this.removeNotifications();
        this.mosaicSelectionAndSearch();
    }
    //Si on est en filtrage sans gesture, on indique qu'on est juste en filtrage.
    else if(_this.currentMode == 'FILTER' && !this.filterSearchedType && !this.curvesGesturesFound)
    {
        this.removeNotifications();
        this.filterSearch();
    }
    //Si on est en filtrage avec gesture, on indique la gesture de filtrage.
    else if(_this.currentMode == 'FILTER' && this.filterSearchedType && !this.curvesGesturesFound)
    {
        this.removeNotifications();
        this.filterGesture(this.filterSearchedType, 'valid');
    }
    
    //On spécifie la marge afin de centrer le prédézoom.
    var margin = this.marginWidth;
    //ID du snapshot précédemment pointé.
    var id = this.previousId;
    //On rétrécit le snapshot de prézoom, puis on le supprime en donnant l'illusion qu'il s'agissait du véritable snapshot, alors qu'en fait c'était un clone.
    for(var i = 0 ; i < this.config.imagesToShow ; i++)
    {
        if($('#prezoomContainer-snapshot-' + i).length > 0)
        {
            $('#prezoomContainer-snapshot-' + i).animate(
            {
                width: this.snapshotWidth + margin,
                height: this.snapshotHeight + margin,
                top: $('#snapshotDiv-' + i).position().top,
                left: $('#snapshotDiv-' + i).position().left
            }, this.config.preUnzoomTime, function(){ $(this).remove(); _this.zoomed = false; });
            $('#prezoomSnapshot-snapshot-' + i).animate(
            {
                width: this.snapshotWidth,
                height: this.snapshotHeight,
                top: $('#snapshotDiv-' + i).position().top,
                left: $('#snapshotDiv-' + i).position().left
            }, this.config.preUnzoomTime);
        }
    }
}


/*
 * Zoom d'un snapshot en plein écran.
 * Est appelé dans les fichiers :
 * zoomInteractions > fonction preZoom.
 * mosaic > fonctions onMouseUp et init.
 */
Mosaic.prototype.zoom = function()
{
    var _this = this;
    
    //Si la mosaïque est en pleine écran, pas la peine de zoomer.
    if(this.currentMode == "VIDEO" || this.currentMode == "SEARCH" || this.currentMode.indexOf("INCOMING") > -1 || this.helpDisplayed || this.isMosaicFiltering)
    {
        return;
    }
	
	//Si on est en mode d'interaction souris, on enlève la bordure d'aide.
	if(this.config.mouseInteractions)
	{
		this.removeHelpIcon();
	}
    
    //On prend les attributs nécessaires au calculs.
    var margin = this.marginWidth, len = this.config.imagesByLine, imgs = this.config.imagesToShow, zoomedMargin = this.config.zoomedMargin;
    var zoomPercentage = this.config.zoomPercentage;
    var initMPWidth = this.previousZoomedSN.width() * len + margin*len, initMPHeight = this.previousZoomedSN.height() * (imgs / len) + margin*(imgs / len);
    var newMPWidth = initMPWidth * len + zoomedMargin * (len), newMPHeight = initMPHeight * (imgs / len) + zoomedMargin * ((imgs / len));
    var newPreMPWidth = initMPWidth * len * zoomPercentage + zoomedMargin * (len), newPreMPHeight = initMPHeight * (imgs / len) * zoomPercentage + zoomedMargin * ((imgs / len));
    
    //Dimensions et coordonnées initiales du div sur lequel on zoom.
    var initialDivWidth = this.previousZoomedSN.width(), initialDivHeight = this.previousZoomedSN.height();
    var initialDivTop = this.previousZoomedSN.position().top, initialDivLeft = this.previousZoomedSN.position().left;
    //Dimensions et coordonnées finales du div.
    var finalDivWidth = initialDivWidth * (zoomPercentage+1), finalDivHeight = initialDivHeight * (zoomPercentage+1);
    var newZoomTop = -this.previousZoomedSN.position().top*(newPreMPHeight/initMPHeight) - zoomedMargin/2 + (initMPHeight - initMPHeight * zoomPercentage)/2, newZoomLeft = -this.previousZoomedSN.position().left*(newPreMPWidth/initMPWidth) - zoomedMargin/2 + (initMPWidth - initMPWidth * zoomPercentage)/2;
    var newSnWidth = initMPWidth * zoomPercentage, newSnHeight = initMPHeight * zoomPercentage;
    
    this.preUnzoom();
    /*SINGULARITE*/
    this.fullscreen = true;
    
    //On passe l'image du snapshot pointé en HD.
    var zoomedImg = $('img', this.previousZoomedSN);
    var src = zoomedImg.attr('src');
    zoomedImg.attr('src', src.replace('-little/', '/'));
    
    //On récupère son ID.
    var tab, zoomedImgId;
    tab = _this.previousId.split('-');
    zoomedImgId = tab[1];
    
    //On donne les dimensions des snapshots.
    $('.snapshotDivs').animate(
    {
        width: newSnWidth,
        height: newSnHeight,
        margin: zoomedMargin/2 + 'px',
    }, this.config.zoomTime);
    
    if(this.currentMode != 'NO-USER')
    {
        //Les snapshots baissent alors en opacité, donnant l'impression qu'ils sont grisés.
        $('.snapshotDivs').animate(
        {
            opacity: '0.4'
        }, this.config.zoomTime);
        //Le snapshot du milieu revient à une opacité optimale, ce qui attire l'attention de l'utilisateur.
        $(this.previousZoomedSN).animate(
        {
            opacity: '1'
        }, this.config.zoomTime);
    }
    //On zoome sur la mosaïque.
    $('#mainPanel').animate(
    {
        width: newPreMPWidth,
        height: newPreMPHeight,
        top: newZoomTop,
        left: newZoomLeft
    }, this.config.zoomTime, function()
    {
		//Si on est en mode d'interaction souris, on affiche la bordure d'aide.
		if(_this.config.mouseInteractions)
		{
			_this.helpIcon();
		}
		
		//Si on est sur une tablette, on affiche l'icone de retour.
		if(_this.isTablet)
		{
			_this.homeIcon();
		}
		
        _this.snTop = (zoomedImg.position().top + newZoomTop + _this.MPTop_margin), _this.snLeft = (zoomedImg.position().left + newZoomLeft);
        _this.snWidth = newSnWidth + 1, _this.snHeight = newSnHeight + 1;
        
        _this.notifyTopVideo = newZoomTop;
        _this.notifyLeftVideo = newZoomLeft;
        
        //On charge les interactions avec les voisins.
        _this.centerId = zoomedImgId;
        
        //Si on n'est pas en mode sans utilisateur, on passe en mode video et on regarde les voisins.
        if(_this.currentMode != "NO-USER")
        {
            _this.currentMode = 'VIDEO';
            _this.listenToNeighbours();
        }
        
        //Si on a une recherche dans cette video.
        if(_this.currentSearchGesture[_this.centerId] != '')
        {
            //On passe en recherche en indiquant la gesture de recherche.
            _this.currentMode = 'SEARCH';
            _this.isCurrentlyInASearchByGesture = true;
            _this.removeNotifications();
            _this.searchGesture(_this.currentSearchGesture[_this.centerId], 'valid');
        }
        
        //On enlève le spinner et on redonne les apparences par défaut aux pointeurs.
        $('#spinner').remove();
        $('#mainPointer').css('background-image', 'url(./img/cursors/pointer.png)');
        $('#secondPointer').css('background-image', 'url(./img/cursors/pointer2.png)');
        
        //On charge le player.
        _this.loadPlayer(_this.snTop, _this.snLeft, _this.snWidth, _this.snHeight, newZoomTop, newZoomLeft, _this.timeToGoAt[_this.centerId]);
    });
}

/*
 * Retour à la taille normale de la mosaïque.
 * Est appelé dans les fichiers :
 * neighbours > fonction checkForDezoom.
 * zoomInteractions > fonction zoom.
 * mosaic > fonctions showNImages et onPlayerLoad.
 */
Mosaic.prototype.unzoom = function()
{
    //Si on n'est pas en plein écran, on quitte.
    if(this.currentMode != "SEARCH" && this.currentMode != "VIDEO" && this.currentMode != "NO-USER" && this.currentMode.indexOf("INCOMING") == -1)
    {
        return;
    }
    
    var _this = this;
	
	//Si on est en mode d'interaction souris, on enlève la bordure d'aide.
	if(this.config.mouseInteractions)
	{
		this.removeHelpIcon();
	}
	
	//Si on est sur une tablette, on enlève l'icone de retour.
	if(this.isTablet)
	{
		this.removeHomeIcon();
	}
    
    //Il n'est plus possible de swiper.
    this.canSwipe = false;
    
    //Si la TL avait été sélectionnée, on la déselectionne.
    if(this.currentMode == 'TIMELINE')
    {
        this.exitTimeline('unzoom');
    }
    
    //On indique qu'on est en train de dezoomer.
    this.currentlyUnzooming = true;
    
    //On supprime les voisins additionnels et on déselectionne les voisins.
    this.removeAdditionalNeighbours();
    this.deselectAllNeighbours();
    
    this.snTop = 0;
    this.snLeft = 0;
    this.Width = 0;
    this.snHeight = 0;
    
    //On charge les attributs nécessaires aux calculs.
    var sWidth = this.snapshotWidth, sHeight = this.snapshotHeight;
    var mpWidth = this.width, mpHeight = this.height;
    var _this = this;
    
    //On passe le snapshot sur lequel on a zoomé en SD.
    var zoomedImg = $('img', this.previousZoomedSN);
    var src = zoomedImg.attr('src');
    zoomedImg.attr('src', src.replace('snapshots/', 'snapshots-little/'));
    
    //On libère le player.
    if(_this.player && _this.player.widgets && _this.player.widgets[0])
    {
        _this.timeToGoAt[_this.centerId] = Math.floor(_this.player.popcorn.currentTime());
        _this.player.widgets[0].freePlayer();
		_this.player = null;
		_this.isVideoReading = false;
    }
    
    //On indique que le player n'est pas prêt et on le supprime.
    _this.playerIsReady = false;
    $('.LdtPlayer').remove();
    $('body').append('<div class="LdtPlayer" id="LdtPlayer"></div>');
    
    //On rend leur opacité aux snapshots. Qui ne sont alors plus grisés.
    $('.snapshotDivs').animate(
    {
        width: sWidth,
        height: sHeight,
        margin: this.marginWidth/2 + 'px'
    }, this.config.unzoomTime, function()
    {
        //Après le dezoom, on indique qu'on a finit de dezoomer.
        _this.neighboursIds.length = 0;
        _this.currentlyUnzooming = false;
    });
    
    //Si l'utilisateur est là.
    if(this.currentMode != 'NO-USER')
    {
        //Si l'utilisateur est déjà au moins d'interaction maximal et que la mosaique n'est pas filtrée, on rend visibles tous les snapshots.
        if(this.currentMode.indexOf("INCOMING") == -1 && !this.isMosaicFiltered)
        {
            $('.snapshotDivs').animate(
            {
                opacity: '1'
            }, this.config.unzoomTime);
        }
        //Si l'utilisateur est déjà au moins d'interaction maximal et que la mosaique est filtrée, on réapplique le filtre sur la mosaique.
        else if(this.currentMode.indexOf("INCOMING") == -1 && this.isMosaicFiltered)
        {
            for(var i = 0 ; i < this.config.imagesToShow ; i++)
            {
                $('#snapshotDiv-' + i).animate(
                {
                    opacity: this.opacities[i]
                }, this.config.unzoomTime);
            }
        }
    }
    //Si on est en mode sans utilisateur.
    else
    {
        //On sélectionne un autre snapshot pour le jouer dans le player.
        this.previousZoomedSN.fadeTo(this.config.unzoomTime, 0, function()
        {
            _this.init();
        });
    }
    
    //On dézoom sur la mosaïque.
    $('#mainPanel').animate(
    {
        width: mpWidth,
        height: mpHeight,
        top: '0px',
        left: '0px'
    }, this.config.unzoomTime, function()
    {
		//Si on est en mode d'interaction souris, on affiche l'icone d'aide.
		if(_this.config.mouseInteractions)
		{
			_this.helpIcon();
		}
		
        //On n'est plus en plein écran, et on ne peut plus se déplacer vers le prochain voisin.
        _this.fullscreen = false;
        _this.canMoveToNeighbour = false;
        
        //Si on est au point d'interaction maximal.
        if(_this.currentMode != 'NO-USER' && _this.currentMode.indexOf('INCOMING-') == -1)
        {
            //Si la mosaique est filtrée, on revient en mode de filtrage, sinon en mode mosaic.
            if(_this.isMosaicFiltered)
            {
                _this.currentMode = 'FILTER';
            }
            else
            {
                _this.currentMode = 'MOSAIC';
            }
            
            //On remet les notifications initiales si on n'est pas dans une recherche par filtrage.
            if(_this.currentMode == 'MOSAIC' && !_this.filterSearchedType)
            {
                _this.removeNotifications();
                _this.mosaicSelectionAndSearch();
            }
			//Sinon on met la gesture en cours.
			else if(_this.currentMode == 'FILTER' && _this.filterSearchedType != '')
			{
				//On notifie.
				_this.removeNotifications();
				_this.filterGesture(_this.filterSearchedType, 'valid');
			}
        }
        
        //On indique qu'on est plus en dezoom.
        this.currentlyUnzooming = false;
    });
}