front_idill/src/mosaic/js/mosaic.js
changeset 30 45c889eae324
child 31 2c7fc855eba8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/front_idill/src/mosaic/js/mosaic.js	Fri Apr 27 14:38:23 2012 +0200
@@ -0,0 +1,596 @@
+/*
+* 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 : mosaic.js
+ * 
+ * Auteur : alexandre.bastien@iri.centrepompidou.fr
+ * 
+ * Fonctionnalités : Définit la "classe" mosaïque et définit des fonctions d'intéractions.
+ */
+
+/*
+ * Classe définissant la mosaïque.
+ * Elle contient sa longueur, le nombre d'images total, une liste d'urls pour les vidéos, leurs snapshots principaux et leur position.
+ * Contient également les dimensions en px de la mosaïque.
+ */
+function mosaic(len, imgToShow, zoomPercentage, prezoomPercentage, zoomedMargin)
+{
+    //S'il s'agit d'un rectangle.
+    if(imgToShow % len == 0)
+    {
+        //Longueur horizontale.
+        this.length = len;
+        //Nombre d'images dans la mosaïque.
+        this.imagesToShow = imgToShow;
+        //Tableaux des urls des vidéos, des snapshots et de leur position dans la mosaïque.
+        this.urls = [];
+        this.imgs = [];
+        this.ids = [];
+        //Dimensions de la mosaïque en pixels.
+        this.width;
+        this.height;
+        //Dimensions d'un snapshot en pixels.
+        this.snapshotWidth;
+        this.snapshotHeight;
+        //Espacement entre les snapshots en pixels.
+        this.marginWidth;
+        
+        //Temps d'intéractions/d'animations.
+        this.preZoomTime;
+        this.preUnzoomTime;
+        this.zoomTime;
+        this.unzoomTime;
+        this.timeNeighbourGlowing;
+        this.timeNeighbourUnglowing;
+        this.timeMovingToNeighbour;
+        
+        //Booléens permettant ou non certaines intéractions selon le contexte.
+        this.zoomed;
+        this.fullscreen;
+        this.canMoveToNeighbour;
+        
+        //Mode actuel.
+        this.currentMode;
+        //Snapshot sur lequel on a zoomé.
+        this.previousZoomedSN;
+        //Son ID.
+        this.previousId;
+        //Largeur de la marge pour le centrage vertical de la mosaïque.
+        this.MPTop_margin;
+        this.top_margin;
+        //Pourcentage d'agrandissement lors d'un prézoom et d'un zoom.
+        this.prezoomPercentage = prezoomPercentage;
+        this.zoomPercentage = zoomPercentage;
+        //Espacement des snapshots après un zoom.
+        this.zoomedMargin = zoomedMargin;
+        //Mosaïque locale.
+        this.localMos;
+        //Position des voisins lors d'un zoom.
+        this.neighboursIds = [];
+        //ID du snapshot du milieu lors d'un zoom.
+        this.centerId;
+    }
+    else
+    {
+        //Affiche un message d'erreur.
+    }
+}
+
+/*
+ * Méthode d'affichage de la mosaïque.
+ * Génère une matrice de imgs.
+ */
+mosaic.prototype.createMosaic = function()
+{
+    this.previousZoomedSN = '';
+    this.previousPrezoomDiv = '';
+    this.fullscreen = false;
+    this.canMoveToNeighbour = false;
+    var str = '';
+    
+    if(this.imgs.length >= this.imagesToShow)
+    {
+        for(var i = 0 ; i < this.imagesToShow ; i++)
+        {
+            //On charge les images de petite taille pour ne pas surcharger la mosaïque lors de l'affichage global.
+            str += '<div id="snapshotDiv-' + i + '" class="snapshotDivs"><img id="snapshot-' + i + '" class="snapshots" src="snapshots-little/' + this.imgs[i] + '" /></div>';
+        }
+    }
+    
+    return str;
+}
+
+/*
+ * Permet de raffraichir la mosaïque.
+ */
+mosaic.prototype.loadMosaic = function(imgsTab)
+{
+    //On affecte les chemins vers les images à la mosaïque.
+    this.imgs = imgsTab;
+    this.previousZoomedSN;
+    //this.width = 
+    //On met à jour la mosaïque.
+    $('#mainPanel').html(this.createMosaic());
+    //On récupère la taille des bordures.
+    this.marginWidth = $('.snapshotDivs').css('margin-bottom');
+    this.marginWidth = parseFloat(mos.marginWidth)*2;
+    //On calcule la taille des divs contenant les snapshots.
+    this.width = $('#mainPanel').innerWidth();
+    //On ne calculera pas tout de suite la hauteur de la mosaique étant donnée qu'elle est calculée par la suite dynamiquement.
+    this.snapshotWidth = this.width / this.length - this.marginWidth;
+    this.snapshotHeight = this.snapshotWidth*9/16;
+    $('.snapshotDivs').css('width', this.snapshotWidth).css('height', this.snapshotHeight).css('margin', this.marginWidth/2);
+    
+    this.height = $('#mainPanel').innerHeight();
+    //On centre verticalement la mosaïque.
+    this.MPTop_margin = ($(document).height() - $('#mainPanel').height())/2;
+    $('#mainPanel').css('margin-top', this.MPTop_margin).css('margin-bottom', this.MPTop_margin);
+}
+
+/*
+ * 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.
+ */
+mosaic.prototype.preZoom = function(snapshot)
+{
+    if(this.fullscreen)
+        return;
+    //Mosaïque.
+    var mosaic = 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.length, imgs = this.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.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)
+        if($('#preZoomContainer-' + currentId) != $(this) && this.previousZoomedSN != '' && this.previousId != '')
+            this.preUnzoom();
+        else
+            return;
+    
+    //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.
+    $('#fake-' + currentId).load(function()
+    {
+        $('#prezoomContainer-' + currentId).css('display', 'block');
+        $('#prezoomContainer-' + currentId).css('top', sTop).css('left', sLeft).css('width', (snWidth + margin)).css('height', (snHeight + margin));
+        $('#prezoomSnapshot-' + currentId).css('width', (snWidth)).css('height', (snHeight));
+        
+        //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;
+        
+        ////Code de debug.
+        ////CAUTION////
+        /*var red = '<div id="red"></div>';
+        if($('#red') != null || $('#red') != undefined)
+            $('body').append(red);
+        $('#red').css('background-color', '#FF0000').css('position', 'absolute').css('top', '0px').css('left', '0px').css('width', '100px').css('height', '100px');
+        $('#red').css('top', finalDivTop).css('left', finalDivLeft).css('width', finalDivWidth).css('height', finalDivHeight);*/
+        //alert("initial : " + initialDivWidth + " " + initialDivHeight + " ; final : " + finalDivWidth + " " + finalDivHeight);
+        ////CAUTION////
+        
+        //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.preZoomTime);
+        $('#prezoomContainer-' + currentId).animate(
+        {
+            width: finalDivWidth + margin*2,
+            height: finalDivHeight - margin,
+            top: finalDivTop + margin,
+            left: finalDivLeft
+        }, this.preZoomTime);
+    });
+    
+    //Si on clique sur le snapshot prézoomé, on enclenche un zoom total sur ce snapshot.
+    $('#prezoomContainer-' + currentId).click(function ()
+    {
+        if(this.previousZoomedSN != '')
+            mosaic.zoom();
+    });
+}
+
+/*
+ * 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é.
+ */
+mosaic.prototype.preUnzoom = function()
+{
+    //Si on n'a pas zoomé, on quitte la fonction.
+    if(!this.zoomed)
+        return;
+    
+    //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 ne zoom plus.
+    this.zoomed = false;
+    //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.
+    $('#prezoomSnapshot-' + id).animate(
+    {
+        width: this.snapshotWidth,
+        height: this.snapshotHeight,
+        top: this.previousZoomedSN.position().top,
+        left: this.previousZoomedSN.position().left
+    }, this.preUnzoomTime);
+    $('#prezoomContainer-' + id).animate(
+    {
+        width: this.snapshotWidth + margin,
+        height: this.snapshotHeight + margin,
+        top: this.previousZoomedSN.position().top,
+        left: this.previousZoomedSN.position().left
+    }, this.preUnzoomTime, function(){ $(this).remove(); this.zoomed = false; });
+}
+
+
+/*
+ * Zoom d'un snapshot en plein écran.
+ */
+mosaic.prototype.zoom = function()
+{
+    var mos = this;
+    
+    //Si la mosaïque est en pleine écran, pas la peine de zoomer.
+    if(this.fullscreen)
+        return;
+    
+    //On prend les attributs nécessaires au calculs.
+    var margin = this.marginWidth, len = this.length, imgs = this.imagesToShow;
+    var initMPWidth = this.previousZoomedSN.width() * len + margin*len, initMPHeight = this.previousZoomedSN.height() * (imgs / len) + margin*(imgs / len);
+    var newMPWidth = initMPWidth * len + this.zoomedMargin * (len), newMPHeight = initMPHeight * (imgs / len) + this.zoomedMargin * ((imgs / len));
+    var newPreMPWidth = initMPWidth * len * this.zoomPercentage + this.zoomedMargin * (len), newPreMPHeight = initMPHeight * (imgs / len) * this.zoomPercentage + this.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 * (this.zoomPercentage+1), finalDivHeight = initialDivHeight * (this.zoomPercentage+1);
+    var newZoomTop = -this.previousZoomedSN.position().top*(newPreMPHeight/initMPHeight) - this.zoomedMargin/2 + (initMPHeight - initMPHeight * this.zoomPercentage)/2 + 'px', newZoomLeft = -this.previousZoomedSN.position().left*(newPreMPWidth/initMPWidth) - this.zoomedMargin/2 + (initMPWidth - initMPWidth * this.zoomPercentage)/2 + 'px';
+    var newSnWidth = initMPWidth * this.zoomPercentage, newSnHeight = initMPHeight * this.zoomPercentage;
+    
+    this.preUnzoom(this);
+    /*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 = mos.previousId.split('-');
+    zoomedImgId = tab[1];
+
+    //Les snapshots baissent alors en opacité, donnant l'impression qu'ils sont grisés.
+    $('.snapshotDivs').animate(
+    {
+        width: newSnWidth,
+        height: newSnHeight,
+        margin: this.zoomedMargin/2 + 'px',
+        opacity: '0.4'
+    }, this.zoomTime);
+    //Le snapshot du milieu revient à une opacité optimale, ce qui attire l'attention de l'utilisateur.
+    $(this.previousZoomedSN).animate(
+    {
+        opacity: '1'
+    }, this.zoomTime);
+    //On zoome sur la mosaïque.
+    $('#mainPanel').animate(
+    {
+        width: newPreMPWidth,
+        height: newPreMPHeight,
+        top: newZoomTop,
+        left: newZoomLeft
+    }, this.zoomTime, function()
+    {
+        //On charge les interactions avec les voisins.
+        mos.centerId = zoomedImgId;
+        mos.listenToNeighbours();
+        mos.currentMode = 'VIDEO';
+        /*mos.unload();
+        mos.localMos.loadLocalMosaic(newZoomTop, newZoomLeft, newSnWidth, newSnHeight, mos.imgs, tab[1]);*/
+    });
+}
+
+/*
+ * Retour à la taille normale de la mosaïque.
+ */
+mosaic.prototype.unzoom = function()
+{
+    //Si on n'est pas en plein écran, on quitte.
+    if(!this.fullscreen)
+        return;
+    
+    //On charge les attributs nécessaires aux calculs.
+    var sWidth = this.snapshotWidth, sHeight = this.snapshotHeight;
+    var mpWidth = this.width, mpHeight = this.height;
+    var mos = this;
+    
+    //On passe le snapshot sur lequel on a zoomé en LD.
+    var zoomedImg = $('img', this.previousZoomedSN);
+    var src = zoomedImg.attr('src');
+    zoomedImg.attr('src', src.replace('snapshots/', 'snapshots-little/'));
+    
+    //On rend leur opacité aux snapshots. Qui ne sont alors plus grisés.
+    $('.snapshotDivs').animate(
+    {
+        width: sWidth,
+        height: sHeight,
+        margin: this.marginWidth/2 + 'px',
+        opacity: '1'
+    }, this.unzoomTime);
+    //On dézoom sur la mosaïque.
+    $('#mainPanel').animate(
+    {
+        width: mpWidth,
+        height: mpHeight,
+        top: '0px',
+        left: '0px'
+    }, this.unzoomTime, function()
+    {
+        //On n'est plus en plein écran, et on ne peut plus se déplacer vers le prochain voisin.
+        mos.fullscreen = false;
+        mos.canMoveToNeighbour = false;
+        //On revient en mode MOSAIC.
+        mos.currentMode = 'MOSAIC';
+        //On ne permet plus le déplacement vers les voisins.
+        $('.snapshotDivs').unbind('mouseenter', mos.changeNeighbourColor);
+    });
+}
+
+/*
+ * Affecte les listeners mouseenter aux voisins lors d'une vue en plein écran.
+ */
+mosaic.prototype.listenToNeighbours = function()
+{
+    ////TEST
+    //$('.test').empty();
+    this.canMoveToNeighbour = false;
+    var currentLine = Math.floor(this.centerId / this.length), currentColumn = this.centerId % this.length;
+    var zoomedImg = $('img', this.previousZoomedSN);
+    var mos = this;
+    
+    //On cherche l'ID des voisins.
+    //Si le voisin de gauche est sur la même ligne, on n'est pas sur la bordure de gauche.
+    this.neighboursIds[0] = (currentColumn > 0) ? (this.centerId - 1) : -1;
+    //Si le voisin de droite est sur la même ligne, on n'est pas sur la bordure de droite.
+    this.neighboursIds[1] = (currentColumn < this.length) ? (+this.centerId + 1) : -1;
+    //Si le voisin du haut est sur la même colonne, on n'est pas sur la bordure du haut.
+    this.neighboursIds[2] = (currentLine > 0) ? (this.centerId - this.length) : -1;
+    //Si le voisin du bas est sur la même colonne, on n'est pas sur la bordure du bas.
+    this.neighboursIds[3] = (currentLine < (this.imagesToShow / this.length)) ? (+this.centerId + this.length) : -1;
+    
+    for(var i = 0 ; i < this.neighboursIds.length ; i++)
+    {
+        if(this.neighboursIds[i] != -1)
+        {
+            //On permet le déplacement vers les voisins.
+            $('#snapshotDiv-' + this.neighboursIds[i]).mouseenter(mos.changeNeighbourColor);
+        }
+    }
+}
+
+/*
+ * Change la coloration d'une bordure où on se positionne lors d'une vue en plein écran.
+ */
+mosaic.prototype.changeNeighbourColor = function()
+{
+    ////TEST
+    //$('.test').append(mos.currentMode + " " + $(this).attr('id') + " " + 'snapshotDiv-' + mos.centerId + ',');
+    
+    //Si on est en mode VIDEO (plein écran) ET si le snapshot pointé est un voisin.
+    if((mos.currentMode == 'VIDEO') && ($(this).attr('id') != 'snapshotDiv-' + mos.centerId))
+    {
+        //On crée le div cyan qui va être superposé au voisin.
+        var cyanDiv = '<div class="cyan" id="cyan-' + $(this).attr('id') + '"></div>';
+        //On le colle au voisin.
+        $('#mainPanel').append(cyanDiv);
+        $('#cyan-' + $(this).attr('id')).css('top', $(this).position().top).css('left', $(this).position().left).css('width', $(this).width()).css('height', $(this).height()).css('margin', $(this).css('margin')).animate(
+        {
+            //On le fait apparaître.
+            opacity: '0.4'
+        }, timeNeighbourUnglowing, function()
+        {
+            //On peut désormais se déplacer vers ce voisin.
+            mos.canMoveToNeighbour = true;
+        }).mouseleave(mos.unchangeNeighbourColor).click(mos.moveToNeighbour);
+    }
+}
+
+/*
+ * Change la coloration d'une bordure quittée lors d'une vue en plein écran.
+ */
+mosaic.prototype.unchangeNeighbourColor = function()
+{
+    ////TEST
+    //$('.test').append('un,');
+    
+    //On ne peut plus se déplacer vers les voisins.
+    mos.canMoveToNeighbour = false;
+    
+    //Si on est en mode VIDEO.
+    if(mos.currentMode == 'VIDEO')
+    {
+        //On obtient le div de coloration superposé au voisin.
+        var cyanDiv = $(this);
+        
+        //On le fait disparaître progressivement.
+        $(this).animate(
+        {
+            opacity: '0'
+        }, timeNeighbourGlowing, function()
+        {
+            //Une fois invisible, on le supprime.
+            cyanDiv.remove();
+        });
+    }
+}
+
+/*
+ * Lors d'une vue en plein écran, on se déplace vers le voisin dont l'id a été spécifié dans la fonction appelante.
+ */
+mosaic.prototype.moveToNeighbour = function()
+{
+    //Si on ne peut pas se déplacer vers les voisins, on quitte.
+    if(!mos.canMoveToNeighbour)
+        return;
+    
+    //On obtient l'ID de destination.
+    var tab = $(this).attr('id').split('-');
+    var destinationId = tab[2];
+    
+    //On charge les attributs nécessaires aux calculs.
+    var MPCurrentTop = $('#mainPanel').position().top, MPCurrentLeft = $('#mainPanel').position().left;
+    var divideCoeffTop = Math.floor(destinationId / mos.length) == 0 ? 1 : Math.floor(destinationId / mos.length);
+    var divideCoeffLeft = destinationId % mos.length == 0 ? 1 : destinationId % mos.length;
+    var cyanTop = $(this).position().top, cyanLeft = $(this).position().left;
+    
+    //On définit pour le déplacement vertical s'il est nécessaire de se déplacer en haut ou en bas.
+    if(mos.previousZoomedSN.position().top > cyanTop)
+        MPCurrentTop += Math.abs(cyanTop - mos.previousZoomedSN.position().top);
+    else if(mos.previousZoomedSN.position().top < cyanTop)
+        MPCurrentTop -= Math.abs(cyanTop - mos.previousZoomedSN.position().top);
+    //On définit pour le déplacement horizontal s'il est nécessaire de se déplacer à gauche ou à droite.
+    if(mos.previousZoomedSN.position().left > cyanLeft)
+        MPCurrentLeft += Math.abs(cyanLeft - mos.previousZoomedSN.position().left);
+    else if(mos.previousZoomedSN.position().left < cyanLeft)
+        MPCurrentLeft -= Math.abs(cyanLeft - mos.previousZoomedSN.position().left);
+    
+    //On passe le snapshot de destination en HD.
+    var destinationImg = $('#snapshot-' + destinationId);
+    var destinationImgSrc = destinationImg.attr('src');
+    destinationImg.attr('src', destinationImgSrc.replace('snapshots-little/', 'snapshots/'));
+    
+    //On passe l'ancien snapshot en LD.
+    var currentImgSrc = $('img', mos.previousZoomedSN).attr('src');
+    $('img', mos.previousZoomedSN).attr('src', currentImgSrc.replace('snapshots/', 'snapshots-little/'));
+    
+    //On obtient l'ID du div de coloration du snapshot vers lequel on se déplace afin de le supprimer.
+    var cyan = $(this);
+    var tab = cyan.attr('id').split('-');
+    mos.centerId = tab[2];
+    $(this).css('opacity', '0');
+    cyan.remove();
+    
+    //On grise le snapshot qu'on vient de quitter.
+    mos.previousZoomedSN.animate(
+    {
+        opacity: '0.4'
+    });
+    
+    //On se déplace.
+    $('#mainPanel').animate(
+    {
+        top: MPCurrentTop,
+        left: MPCurrentLeft
+    }, timeMovingToNeighbour, function()
+    {
+        //On fait apparaître le snapshot vers lequel on s'est déplacé.
+        $('#snapshotDiv-' + destinationId).animate(
+        {
+            opacity: '1'
+        }, mos.zoomTime, function()
+        {
+            //On recharge les voisins.
+            $('.snapshotDivs').unbind('mouseenter', mos.changeNeighbourColor);
+            mos.previousZoomedSN = $('#snapshotDiv-' + mos.centerId);
+            mos.listenToNeighbours();
+        });
+    });
+}
+
+/*
+ * Déchargement du contenu de la mosaïque pour le chargement de la mosaïque locale.
+ */
+mosaic.prototype.unload = function()
+{
+    //On supprime les event listeners des objets de la mosaïque.
+    $('.snapshotDivs').unbind();
+    $('.snapshots').unbind();
+    $('.prezoomContainers').unbind();
+    //On supprime physiquement les objets.
+    $('#mainPanel').empty();
+}
+
+/*
+ * Centre verticalement un snapshot.
+ */
+/*function verticalCenterImg(mosaic, img)
+{
+    //On récupère sa hauteur.
+    var image_height = img.height();
+    //Calcule la marge du haut de chaque div pour le centrage.
+    if(mosaic.top_margin == undefined)
+        mosaic.top_margin = (mosaic.snapshotHeight > image_height) ? (mosaic.snapshotHeight - image_height)/2 : (image_height - mosaic.snapshotHeight)/2;
+    //On centre le snapshot.
+    img.css('margin-top', mosaic.top_margin).css('margin-bottom', mosaic.top_margin);
+}*/
+
+/*
+ * Permet de tester l'égalité des éléments de deux objets.
+ * Pour ce faire on compare les éléments définissant ces objets.
+ */
+$.fn.equals = function(compareTo)
+{
+    if (!compareTo || !compareTo.length || this.length!=compareTo.length)
+    {
+        return false;
+    }
+    for (var i=0; i<this .length; i++)
+    {
+        if (this[i]!==compareTo[i])
+        {
+            return false;
+        }
+    }
+    return true;
+}
\ No newline at end of file