front_idill/src/mosaic/js/mosaic.js
changeset 35 4267d6d27a7d
parent 33 2d9b15f99b4e
child 44 8393d3473b98
--- a/front_idill/src/mosaic/js/mosaic.js	Thu May 24 10:35:27 2012 +0200
+++ b/front_idill/src/mosaic/js/mosaic.js	Wed May 30 10:21:36 2012 +0200
@@ -22,96 +22,75 @@
  * 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, imgTotal, zoomPercentage, prezoomPercentage, zoomedMargin)
+function mosaic(config, default_conf)
 {
-    //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;
-		this.imagesTotal = imgTotal;
-        //Tableaux des urls des vidéos, des snapshots et de leur position dans la mosaïque.
-        this.videos = [];
-        this.urls = [];
-        this.imgs = [];
-        this.ids = [];
-		//On remplit le tableau d'ids.
-		for(var i = 0 ; i < this.imagesTotal ; i++)
-			this.ids.push(i);
-		//On les mélange.
-		this.ids.sort(function()
-		{
-			return 0.5 - Math.random()
-		});
-		
-		console.log(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;
-		this.timeSearchFade;
-		this.timeNotifyFade;
-        
-        //Booléens permettant ou non certaines intéractions selon le contexte.
-        this.zoomed;
-        this.fullscreen;
-        this.canMoveToNeighbour;
-		this.helpDisplayed;
-        
-        //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;
-		
-		//Lecteur.
-		this.player;
-		
-		//Coordonnées et dimensions d'un snapshot zoomé.
-		this.snTop = 0;
-		this.snLeft = 0;
-		this.snWidth = 0;
-		this.snHeight = 0;
-		
-		this.searchCanvas;
-		
-		this.loadFromJson('./player/json/videos.json');
-    }
-    else
-    {
-        //Affiche un message d'erreur.
-    }
+	//Chemin du fichier de configuration.
+	this.config_path = config;
+	//Configuration par défaut en cas de valeur erronnée.
+	this.default_config = default_conf;
+	this.config = new Object();
+	//Tableaux des urls des vidéos, des snapshots et de leur position dans la mosaïque.
+	this.videos = [];
+	this.urls = [];
+	this.imgs = [];
+	this.ids = [];
+	this.fillingIds = [];
+	this.currentRandomVideoIdx = 0;
+	
+	//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;
+	
+	//Booléens permettant ou non certaines intéractions selon le contexte.
+	this.zoomed;
+	this.fullscreen;
+	this.canMoveToNeighbour;
+	this.helpDisplayed;
+	
+	//Type de marqueur recherché dans la mosaïque (en mode filter).
+	this.filterSearchedType = "";
+	
+	//Mode actuel.
+	this.currentMode = "MOSAIC";
+	//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;
+
+	//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;
+	
+	//Snapshots a afficher.
+	this.snapshotsToShow = 1;
+	
+	//Lecteur.
+	this.player;
+	//Annotations (pour les marqueurs los d'un filtrage).
+	this.annotations = [];
+	
+	//Coordonnées et dimensions d'un snapshot zoomé.
+	this.snTop = 0;
+	this.snLeft = 0;
+	this.snWidth = 0;
+	this.snHeight = 0;
+	
+	this.searchCanvas;
+	//Position actuelle de la vidéo zoomée.
+	this.notifyTopVideo;
+	this.notifyLeftVideo;
+	this.loadParameters(this.config_path);
 }
 
 /*
@@ -120,25 +99,48 @@
  */
 mosaic.prototype.createMosaic = function()
 {
-    this.previousZoomedSN = '';
-    this.previousPrezoomDiv = '';
-    this.fullscreen = false;
-    this.canMoveToNeighbour = false;
-	this.helpDisplayed = false;
-    var str = '';
-    
-    if(this.imgs.length >= this.imagesToShow)
+	console.log('CREATE');
+	this.currentMode = "NO-USER";
+	var initPanel = '<div id="initPanel"></div>';
+	var mp = $('#mainPanel');
+	mp.append(initPanel);
+	$('#initPanel').css(
+	{
+		background: 'transparent',
+		width: mp.width(),
+		height: mp.height(),
+		top: mp.position().top,
+		left: mp.position().left,
+		'margin-top': this.MPTop_margin
+	});
+	
+	var len = this.config['length'], imgs = this.config['imagesToShow'], imgsTotal = this.config['imagesTotal'];
+	
+	//S'il s'agit d'un rectangle.
+    if(imgs % len == 0)
     {
-        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>';
-        }
-    }
-    
-	console.log(this.imagesToShow);
-	
-    return str;
+		this.previousZoomedSN = '';
+		this.previousPrezoomDiv = '';
+		this.fullscreen = false;
+		this.canMoveToNeighbour = false;
+		this.helpDisplayed = false;
+		var str = '';
+		
+		if(this.imgs.length >= imgs)
+		{
+			for(var i = 0 ; i < imgs ; 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" style="opacity: 0;"><img id="snapshot-' + i + '" class="snapshots" src="snapshots-little/' + this.imgs[i] + '" /></div>';
+			}
+		}
+		
+		return str;
+	}
+	else
+	{
+		alert("Le nombre d'images a afficher doit être divisible par la longueur de la mosaïque !");
+	}
 }
 
 /*
@@ -146,6 +148,7 @@
  */
 mosaic.prototype.loadMosaic = function()
 {
+	console.log('LOAD');
 	var createMosaic = this.createMosaic();
 	
 	if(createMosaic == '')
@@ -162,11 +165,11 @@
     $('#mainPanel').html(createMosaic);
     //On récupère la taille des bordures.
     this.marginWidth = $('.snapshotDivs').css('margin-bottom');
-    this.marginWidth = parseFloat(mos.marginWidth)*2;
+    this.marginWidth = parseFloat(this.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.snapshotWidth = this.width / this.config['length'] - this.marginWidth;
     this.snapshotHeight = this.snapshotWidth*9/16;
     $('.snapshotDivs').css('width', this.snapshotWidth).css('height', this.snapshotHeight).css('margin', this.marginWidth/2);
     
@@ -183,17 +186,287 @@
 		//On effectue un prézoom dès qu'on va sur une image.
 		_this.preZoom($(this));
 	});
-	$('body').keypress(function (event)
+	
+	this.addPointers();
+	
+	//Si dans le metadata player _ n'est pas déclaré, on le déclare.
+	if(typeof _ !== "undefined" && typeof IriSP._ === "undefined")
+	{
+		IriSP._ = _;
+	}
+	
+	if(typeof $ !== "undefined" && typeof IriSP.jQuery === "undefined")
+	{
+		IriSP.jQuery = $;
+	}
+	
+	//On charge les marqueurs.
+	var sourceManager = new IriSP.Model.Directory(),
+	globalAnnotations = new IriSP.Model.List(sourceManager),
+	nbFichiers = _this.urls.length,
+	fichiersCharges = 0;
+	
+	for (var i = 0; i < nbFichiers; i++)
+	{
+		console.log('url : ' + _this.urls[i]);
+		var source = sourceManager.remoteSource({url: _this.urls[i], serializer: IriSP.serializers.ldt});
+		source.onLoad(function()
+		{
+			globalAnnotations.addElements(source.getAnnotations());
+			fichiersCharges++;
+			if (fichiersCharges == nbFichiers)
+			{
+				// instructions à exécuter quand tout est chargé
+				_this.annotations = globalAnnotations;
+				console.log('annotations loaded');
+				_this.init();
+			}
+		});
+	}
+}
+
+/*
+ * Charge les paramètres du Front. Local (true/false) est le mode de chargement des données.
+*/
+mosaic.prototype.loadParameters = function(file_path)
+{
+	var _this = this;
+	
+	var supposedToBeInt = ['length', 'imagesToShow', 'totalImages', 'timePrezoom', 'timePreUnzoom', 'timeZoom', 'timeUnzoom', 'timeNeighbourGlowing', 'timeNeighbourUnglowing', 'timeMovingToNeighbour', 'timeSearchFade', 'timeNotifyFade', 'timeFilterFade', 'timeFilling', 'zoomedMargin'];
+	var supposedToBeFloat = ['zoomPercentage', 'prezoomPercentage'];
+	
+	$.getJSON(file_path, function(data)
 	{
-		//Si on a appuié sur la touche 'q' ou 'Q';
-		if(event.which == 113 || event.which == 81)
+		for(key in data)
 		{
-		   _this.unzoom();
+			var val = data[key];
+			
+			if(_.include(supposedToBeInt, key))
+			{
+				var intVal = parseInt(val);
+				if(isNaN(intVal))
+				{
+					console.log(_this.default_config);
+					_this.config[key] = _this.default_config[key];
+					console.log("param[" + key + "] : Valeur " + val + " incorrecte (non Int). Valeur par défaut " + _this.default_config[key] + " chargée à la place.");
+				}
+				else
+				{
+					_this.config[key] = intVal;
+				}
+			}
+			else if(_.include(supposedToBeFloat, key))
+			{
+				var floatVal = parseFloat(val);
+				if(isNaN(floatVal))
+				{
+					_this.config[key] = _this.default_config[key];
+					console.log("param[" + key + "] : Valeur " + val + " incorrecte (non Float). Valeur par défaut " + _this.default_config[key] + " chargée à la place.");
+				}
+				else
+				{
+					_this.config[key] = floatVal;
+				}
+			}
+			else
+			{
+				_this.config[key] = val;
+			}
+		}
+		
+		//On remplit le tableau d'ids.
+		for(var i = 0 ; i < _this.config['totalImages'] ; i++)
+			_this.ids.push(i);
+		//On les mélange.
+		_this.ids.sort(function()
+		{
+			return 0.5 - Math.random()
+		});
+		
+		//On remplit le tableau d'ids destiné à afficher les snapshots au fur et à mesure.
+		for(var i = 0 ; i < _this.config['imagesToShow'] ; i++)
+			_this.fillingIds.push(i);
+		//On les mélange.
+		_this.fillingIds.sort(function()
+		{
+			return 0.5 - Math.random()
+		});
+		
+		if(_this.config['local'] == 'true')
+		{
+			console.log("Loading local metadata.");
+			_this.loadFromJson('./player/json/local_videos.json');
+		}
+		else
+		{
+			console.log("Loading online metadata.");
+			_this.loadFromJson('./player/json/online_videos.json');
 		}
 	});
 }
 
 /*
+ * Phase principale (utilisateur non détecté). Une vidéo se lance aléatoirement.
+ * L'interface est identique à celle du zoom, mais sans interaction possible avec les voisins, ni les controles timeline.
+ * Lors de la fin d'une lecture, on dézoome vers la mosaïque, puis on rezoome vers un autre snapshot (aléatoire).
+*/
+mosaic.prototype.init = function()
+{
+	var _this = this;
+	
+	if(this.currentRandomVideoIdx > this.config['imagesToShow'])
+	{
+		this.currentRandomVideoIdx = 0;
+	}
+	
+	this.previousZoomedSN = $('#snapshotDiv-' + this.fillingIds[this.currentRandomVideoIdx]);
+	this.previousId = $('img', this.previousZoomedSN).attr('id');
+	
+	console.log('ids', this.fillingIds[this.currentRandomVideoIdx]);
+	
+	this.previousZoomedSN.fadeTo(this.config['timePrezoom'], 1, function()
+	{
+		_this.zoom();
+		_this.currentRandomVideoIdx++;
+	});
+}
+
+/*
+ * Remplissage de la mosaïque en fonction du nombre d'images à afficher.
+*/
+mosaic.prototype.showNImages = function(n)
+{
+	if(n > 1)
+	{
+		this.currentMode = "INCOMING-" + n;
+		this.unzoom();
+	}
+	
+	for(var i = 0 ; i < n ; i++)
+	{
+		if($('#snapshotDiv-' + i).css('opacity') < 1)
+		{
+			$('#snapshotDiv-' + i).fadeTo(this.config['timeFilling'], 1);
+		}
+	}
+}
+
+/*
+ * Affiche les pointeurs.
+*/
+mosaic.prototype.addPointers = function()
+{
+	var _this = this;
+	
+	var mainPointer = '<div id="mainPointer" class="pointers"></div>';
+	$('body').append(mainPointer);
+	$('body').mousemove(function(evt)
+	{
+		$('#mainPointer').css(
+		{
+			top: evt.pageY - $('#mainPointer').height()/2,
+			left: evt.pageX - $('#mainPointer').width()/2
+		});
+	});
+}
+
+/*
+ * Gère les événements de contrôle dans la mosaïque.
+*/
+mosaic.prototype.manageControlEvents = function(event)
+{
+	console.log('manage');
+	//Sinon si on a appuyé sur 'g' ou 'G'.
+	if(event.which == 103 || event.which == 71)
+	{
+		//Si on est déjà en recherche par courbes.
+		if(this.currentMode == "SEARCH" || this.currentMode == "FILTER")
+		{
+			//On quitte cette recherche.
+			this.leaveSearch();
+			//Si on était en mode recherche.
+			if(this.currentMode == "SEARCH")
+			{
+				//On revient dans la vidéo.
+				this.currentMode = "VIDEO";
+			}
+			else
+			{
+				//Sinon c'est qu'on était dans la mosaïque.
+				this.currentMode = "MOSAIC";
+			}
+		}
+		else
+		{
+			//Si on est en plein écran.
+			if(this.fullscreen)
+			{
+				//On entre en mode recherche.
+				this.currentMode = "SEARCH";
+			}
+			//Sinon.
+			else
+			{
+				//On entre en mode filtrage.
+				this.currentMode = "FILTER";
+			}
+			
+			this.startSearch();
+		}
+	}
+	//Si c'est a ou A.
+	else if(event.which == 65 || event.which == 97)
+	{
+		if(!this.helpDisplayed)
+		{
+			this.notifyHelp();
+		}
+		else
+		{
+			this.removeHelp();
+		}
+	}
+	//Si c'est v ou V.
+	else if(event.which == 86 || event.which == 118)
+	{
+		this.notifySearchMarkers('run;jump;fall');
+	}
+	//Si c'est b ou B.
+	else if(event.which == 66 || event.which == 98)
+	{
+		this.removeSearchMarkers();
+	}
+	//Si c'est k ou K.
+	else if(event.which == 75 || event.which == 107)
+	{
+		this.searchFilter('circle');
+	}
+	//Si c'est l ou L.
+	else if(event.which == 76 || event.which == 108)
+	{
+		this.removeFilter();
+	}
+	//Si on a appuié sur la touche 'q' ou 'Q';
+	else if(event.which == 113 || event.which == 81)
+	{
+		this.unzoom();
+	}
+	else if(event.which == 111 || event.which == 79)
+	{
+		if(this.snapshotsToShow > this.imagesToShow)
+		{
+			this.snapshotsToShow = this.imagesToShow;
+		}
+		else
+		{
+			this.snapshotsToShow += 5;
+		}
+		
+		this.showNImages(this.snapshotsToShow);
+	}
+}
+
+/*
  * 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.
  */
@@ -208,15 +481,15 @@
 	this.removeSelectionSearchMosaicFull();
 	
     //Mosaïque.
-    var mosaic = this;
+    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.length, imgs = this.imagesToShow, margin = this.marginWidth;
+    var len = this.config['length'], 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.prezoomPercentage;
+    var prezoomPercentage = this.config['prezoomPercentage'];
     
     //ID de l'image actuelle.
     var currentId = $('img', snapshot).attr('id');
@@ -297,16 +570,16 @@
             height: finalDivHeight - margin*2,
             top: finalDivTop + margin,
             left: finalDivLeft + margin
-        }, this.preZoomTime);
+        }, _this.config['timePrezoom']);
         $('#prezoomContainer-' + currentId).animate(
         {
             width: finalDivWidth + margin*2,
             height: finalDivHeight - margin,
             top: finalDivTop + margin,
             left: finalDivLeft
-        }, this.preZoomTime, function()
+        }, _this.config['timePrezoom'], function()
 		{
-			mosaic.notifyPointMosaicPrezoom();
+			_this.notifyPointMosaicPrezoom();
 		});
     });
     
@@ -315,7 +588,7 @@
     {
         if(this.previousZoomedSN != '')
 		{
-            mosaic.zoom();
+            _this.zoom();
 		}
     });
 }
@@ -346,14 +619,14 @@
         height: this.snapshotHeight,
         top: this.previousZoomedSN.position().top,
         left: this.previousZoomedSN.position().left
-    }, this.preUnzoomTime);
+    }, this.config['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; });
+    }, this.config['preUnzoomTime'], function(){ $(this).remove(); this.zoomed = false; });
 }
 
 
@@ -362,10 +635,10 @@
  */
 mosaic.prototype.zoom = function()
 {
-    var mos = this;
+    var _this = this;
     
     //Si la mosaïque est en pleine écran, pas la peine de zoomer.
-    if(this.fullscreen)
+    if(this.currentMode == "VIDEO" || this.currentMode == "SEARCH")
 	{
         return;
 	}
@@ -373,18 +646,19 @@
 	this.removePointMosaicPrezoom();
     
     //On prend les attributs nécessaires au calculs.
-    var margin = this.marginWidth, len = this.length, imgs = this.imagesToShow;
+    var margin = this.marginWidth, len = this.config['length'], 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 + 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));
+    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 * (this.zoomPercentage+1), finalDivHeight = initialDivHeight * (this.zoomPercentage+1);
-    var newZoomTop = -this.previousZoomedSN.position().top*(newPreMPHeight/initMPHeight) - this.zoomedMargin/2 + (initMPHeight - initMPHeight * this.zoomPercentage)/2, newZoomLeft = -this.previousZoomedSN.position().left*(newPreMPWidth/initMPWidth) - this.zoomedMargin/2 + (initMPWidth - initMPWidth * this.zoomPercentage)/2;
-    var newSnWidth = initMPWidth * this.zoomPercentage, newSnHeight = initMPHeight * this.zoomPercentage;
+    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(this);
     /*SINGULARITE*/
@@ -397,22 +671,31 @@
     
     //On récupère son ID.
     var tab, zoomedImgId;
-    tab = mos.previousId.split('-');
+    tab = _this.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 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(
     {
@@ -420,22 +703,24 @@
         height: newPreMPHeight,
         top: newZoomTop,
         left: newZoomLeft
-    }, this.zoomTime, function()
+    }, this.config['zoomTime'], function()
     {
         //On charge les interactions avec les voisins.
-        mos.centerId = zoomedImgId;
-        mos.listenToNeighbours();
-        mos.currentMode = 'VIDEO';
+        _this.centerId = zoomedImgId;
+		
+		if(_this.currentMode != "NO-USER")
+		{
+			_this.currentMode = 'VIDEO';
+			_this.listenToNeighbours();
+		}
 		
-		console.log('h : ' + -newZoomLeft + " " + zoomedImg.position().left);
-
-		mos.snTop = (zoomedImg.position().top + newZoomTop + mos.MPTop_margin), mos.snLeft = (zoomedImg.position().left + newZoomLeft);
-		mos.snWidth = newSnWidth + 1, mos.snHeight = newSnHeight + 1;
+		_this.snTop = (zoomedImg.position().top + newZoomTop + _this.MPTop_margin), _this.snLeft = (zoomedImg.position().left + newZoomLeft);
+		_this.snWidth = newSnWidth + 1, _this.snHeight = newSnHeight + 1;
 		
-		mos.loadPlayer(mos.snTop, mos.snLeft, mos.snWidth, mos.snHeight, newZoomTop, newZoomLeft);
+		_this.notifyTopVideo = newZoomTop;
+		_this.notifyLeftVideo = newZoomLeft;
 		
-        /*mos.unload();
-        mos.localMos.loadLocalMosaic(newZoomTop, newZoomLeft, newSnWidth, newSnHeight, mos.imgs, tab[1]);*/
+		_this.loadPlayer(_this.snTop, _this.snLeft, _this.snWidth, _this.snHeight, newZoomTop, newZoomLeft);
     });
 }
 
@@ -444,20 +729,20 @@
 */
 mosaic.prototype.loadPlayer = function(newZoomTop, newZoomLeft, newSnWidth, newSnHeight, zoomTop, zoomLeft)
 {
+	var _this = this;
+	
 	//On configure les options de lancement.
 	IriSP.libFiles.defaultDir = "../lib/";
 	IriSP.widgetsDir = "./player/metadataplayer/"
 	
 	var videoToPlay = this.videos[this.centerId];
 	var currentMetadata = this.urls[this.centerId];
-	console.log('VIDEO[' + this.centerId + '] : ' + videoToPlay);
-	console.log('MD[' + this.centerId + '] : ' + currentMetadata);
 	
 	var _metadata = {
 		url: currentMetadata,
 		format: 'ldt'
 	};
-	console.log(zoomTop + " m" + this.marginWidth);
+	
 	var _config = {
 		gui: {
 			zoomTop: zoomTop - this.marginWidth*2,
@@ -498,6 +783,23 @@
 	//On démarre le player.
 	this.player = null;
 	this.player = new IriSP.Metadataplayer(_config, _metadata);
+	
+	if(this.currentMode == 'NO-USER')
+	{
+		this.player.onLoad(function()
+		{
+			console.log(_this.player);
+			console.log(_this.player.popcorn);
+			//Lorsque le player est en pause (par exemple lorsque le curseur arrive à la fin de la timeline).
+			if(_this.player.popcorn != undefined)
+			{
+				_this.player.popcorn.listen('pause', function()
+				{
+					_this.unzoom();
+				});
+			}
+		});
+	}
 }
 
 /*
@@ -506,7 +808,8 @@
 mosaic.prototype.unzoom = function()
 {
     //Si on n'est pas en plein écran, on quitte.
-    if(!this.fullscreen)
+	console.log("'" + this.currentMode + "'");
+    if(this.currentMode != "SEARCH" && this.currentMode != "VIDEO" && this.currentMode != "NO-USER" && this.currentMode.indexOf("INCOMING") == -1)
 	{
         return;
 	}
@@ -519,25 +822,45 @@
     //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;
+    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/'));
 	
-	mos.player.widgets[0].freePlayer();
+	_this.player.widgets[0].freePlayer();
 	$('.LdtPlayer').remove();
 	$('body').append('<div class="LdtPlayer" id="LdtPlayer"></div>');
+	_this.reaffectKeyPress();
     
     //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);
+        margin: this.marginWidth/2 + 'px'
+    }, this.config['unzoomTime']);
+	
+	if(this.currentMode != 'NO-USER')
+	{
+		if(this.currentMode.indexOf("INCOMING") == -1)
+		{
+			$('.snapshotDivs').animate(
+			{
+				opacity: '1'
+			}, this.config['unzoomTime']);
+		}
+	}
+	else
+	{
+		console.log('init');
+		this.previousZoomedSN.fadeTo(this.config['unzoomTime'], 0, function()
+		{
+			_this.init();
+		});
+	}
+	
     //On dézoom sur la mosaïque.
     $('#mainPanel').animate(
     {
@@ -545,17 +868,24 @@
         height: mpHeight,
         top: '0px',
         left: '0px'
-    }, this.unzoomTime, function()
+    }, this.config['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.selectNeighbour);
-		//On remet les notifications initiales.
-		mos.notifySelectionSearchMosaicFull();
+        _this.fullscreen = false;
+        _this.canMoveToNeighbour = false;
+		
+		if(_this.currentMode != 'NO-USER')
+		{
+			//On revient en mode MOSAIC.
+			_this.currentMode = 'MOSAIC';
+			//On ne permet plus le déplacement vers les voisins.
+			$('.snapshotDivs').unbind('mouseover', function()
+			{
+				_this.selectNeighbour();
+			});
+			//On remet les notifications initiales.
+			_this.notifySelectionSearchMosaicFull();
+		}
     });
 }
 
@@ -566,20 +896,21 @@
 {
     ////TEST
     //$('.test').empty();
-    this.canMoveToNeighbour = false;
-    var currentLine = Math.floor(this.centerId / this.length), currentColumn = this.centerId % this.length;
+    var _this = this;
+    
+	this.canMoveToNeighbour = false;
+    var currentLine = Math.floor(this.centerId / this.config['length']), currentColumn = this.centerId % this.config['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;
+    this.neighboursIds[1] = (currentColumn < this.config['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;
+    this.neighboursIds[2] = (currentLine > 0) ? (this.centerId - this.config['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;
+    this.neighboursIds[3] = (currentLine < (this.config['imagesToShow'] / this.config['length'])) ? (+this.centerId + this.config['length']) : -1;
     
 	//ID du cadre voisin.
 	var preId;
@@ -591,7 +922,11 @@
 			preId = '#neighbourFrameBorder-' + this.neighboursIds[i];
             //On permet le déplacement vers les voisins.
             // $('#snapshotDiv-' + this.neighboursIds[i] + ', ' + preId + '-left,' + preId + '-right,' + preId + '-up,' + preId + '-down').mouseenter(mos.selectNeighbour);
-            $('#snapshotDiv-' + this.neighboursIds[i]).mouseenter(mos.selectNeighbour);
+			
+            $('#snapshotDiv-' + this.neighboursIds[i]).mouseover(function()
+			{
+				_this.selectNeighbour($(this));
+			});
         }
     }
 }
@@ -599,20 +934,22 @@
 /*
  * Change la coloration d'une bordure où on se positionne lors d'une vue en plein écran.
  */
-mosaic.prototype.selectNeighbour = function()
+mosaic.prototype.selectNeighbour = function(neighbour)
 {
     ////TEST
     //$('.test').append(mos.currentMode + " " + $(this).attr('id') + " " + 'snapshotDiv-' + mos.centerId + ',');
-    
+	var _this = this;
+	
     //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))
-    {
+    
+    if((this.currentMode == 'VIDEO') && (neighbour.attr('id') != 'snapshotDiv-' + this.centerId))
+    {
         //On crée le cadre qui va être superposé au voisin.
         //On le colle au voisin.
-		var tab = $(this).attr('id').split('-');
+		var tab = neighbour.attr('id').split('-');
 		var snapshotId = tab[1];
         var neighbourFrame = '';
-		var marginValue = parseFloat($(this).css('margin'));
+		var marginValue = parseFloat(neighbour.css('margin'));
 		
 		neighbourFrame += '<div class="neighbourFrame" id="neighbourFrame-' + snapshotId + '"><div class="neighbourImgBg" id="neighbourImgBg-' + snapshotId + '"><div class="neighbourImg" id="neighbourImg-' + snapshotId + '"></div></div></div>';
 		
@@ -621,28 +958,28 @@
 		//On positionne le div de background juste au niveau du voisin.
         $('#neighbourFrame-' + snapshotId).css(
 		{
-			'top': (+$(this).position().top + marginValue),
-			'left': (+$(this).position().left + marginValue),
-			'width': $(this).width(),
-			'height': $(this).height()
+			'top': (+neighbour.position().top + marginValue),
+			'left': (+neighbour.position().left + marginValue),
+			'width': neighbour.width(),
+			'height': neighbour.height()
 		});
 		//On positionne le div de background noir juste au niveau de l'image du voisin.
         $('#neighbourImgBg-' + snapshotId).css(
 		{
 			'top': marginValue,
 			'left': marginValue,
-			'width': $(this).width() - marginValue*2,
-			'height': $(this).height() - marginValue*2,
+			'width': neighbour.width() - marginValue*2,
+			'height': neighbour.height() - marginValue*2,
 		});
 		//On met par dessus le div de l'image clonée du voisin.
 		$('#neighbourImg-' + snapshotId).css(
 		{
 			'top': 0,
 			'left': 0,
-			'width': $(this).width() - marginValue*2,
-			'height': $(this).height() - marginValue*2,
-			'background-image': 'url("' + $('img', $(this)).attr('src') + '")',
-			'background-size': $(this).width() + 'px ' + $(this).height() + 'px',
+			'width': neighbour.width() - marginValue*2,
+			'height': neighbour.height() - marginValue*2,
+			'background-image': 'url("' + $('img', neighbour).attr('src') + '")',
+			'background-size': neighbour.width() + 'px ' + neighbour.height() + 'px',
 			'background-position': -marginValue + 'px ' + -marginValue + 'px',
 			'opacity': '0.4'
 		});
@@ -653,40 +990,45 @@
         {
             //On le fait apparaître.
             opacity: '1'
-        }, timeNeighbourGlowing, function()
+        }, _this.config['timeNeighbourGlowing'], function()
         {
             //On peut désormais se déplacer vers ce voisin.
-            mos.canMoveToNeighbour = true;
+            _this.canMoveToNeighbour = true;
         });
 		//Lorsqu'on quitte un des snapshots (bien entendu le voisin en question), on retire le cadre.
-		$(fId).mouseleave(mos.deselectNeighbour)
 		//Si on clique sur le voisin ou son cadre, on passe au voisin suivant.
-		$(fId).click(mos.moveToNeighbour);
+		$(fId).mouseout(function()
+		{
+			_this.deselectNeighbour($(this))
+		}).click(function()
+		{
+			_this.moveToNeighbour($(this))
+		});
     }
 }
 
 /*
  * Change la coloration d'une bordure quittée lors d'une vue en plein écran.
  */
-mosaic.prototype.deselectNeighbour = function()
+mosaic.prototype.deselectNeighbour = function(neighbour)
 {
     ////TEST
     //$('.test').append('un,');
 	
     //On ne peut plus se déplacer vers les voisins.
-    mos.canMoveToNeighbour = false;
+    this.canMoveToNeighbour = false;
     
 	//On récupère le voisin.
-	var neighbourFrame = $(this);
+	var neighbourFrame = neighbour;
 	
     //Si on est en mode VIDEO.
-    if(mos.currentMode == 'VIDEO')
+    if(this.currentMode == 'VIDEO')
     {
         //On le fait disparaître progressivement.
         neighbourFrame.animate(
         {
             opacity: '0'
-        }, timeNeighbourUnglowing, function()
+        }, this.config['timeNeighbourUnglowing'], function()
         {
             //Une fois invisible, on le supprime.
             neighbourFrame.remove();
@@ -697,34 +1039,36 @@
 /*
  * 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()
-{
+mosaic.prototype.moveToNeighbour = function(neighbour)
+{
+	var _this = this;
     //Si on ne peut pas se déplacer vers les voisins, on quitte.
-    if(!mos.canMoveToNeighbour)
+    if(!_this.canMoveToNeighbour)
 	{
         return;
 	}
     
     //On obtient l'ID de destination.
-    var tab = $(this).attr('id').split('-');
+    var tab = neighbour.attr('id').split('-');
     var destinationId = tab[1];
     
     //On charge les attributs nécessaires aux calculs.
+	var length = _this.config['length'];
     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 divideCoeffTop = Math.floor(destinationId / length) == 0 ? 1 : Math.floor(destinationId / length);
+    var divideCoeffLeft = destinationId % length == 0 ? 1 : destinationId % length;
     var neighbourFrameTop = $('#snapshotDiv-' + destinationId).position().top, neighbourFrameLeft = $('#snapshotDiv-' + destinationId).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 > neighbourFrameTop)
-        MPCurrentTop += Math.abs(neighbourFrameTop - mos.previousZoomedSN.position().top);
-    else if(mos.previousZoomedSN.position().top < neighbourFrameTop)
-        MPCurrentTop -= Math.abs(neighbourFrameTop - mos.previousZoomedSN.position().top);
+    if(_this.previousZoomedSN.position().top > neighbourFrameTop)
+        MPCurrentTop += Math.abs(neighbourFrameTop - _this.previousZoomedSN.position().top);
+    else if(_this.previousZoomedSN.position().top < neighbourFrameTop)
+        MPCurrentTop -= Math.abs(neighbourFrameTop - _this.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 > neighbourFrameLeft)
-        MPCurrentLeft += Math.abs(neighbourFrameLeft - mos.previousZoomedSN.position().left);
-    else if(mos.previousZoomedSN.position().left < neighbourFrameLeft)
-        MPCurrentLeft -= Math.abs(neighbourFrameLeft - mos.previousZoomedSN.position().left);
+    if(_this.previousZoomedSN.position().left > neighbourFrameLeft)
+        MPCurrentLeft += Math.abs(neighbourFrameLeft - _this.previousZoomedSN.position().left);
+    else if(_this.previousZoomedSN.position().left < neighbourFrameLeft)
+        MPCurrentLeft -= Math.abs(neighbourFrameLeft - _this.previousZoomedSN.position().left);
     
     //On passe le snapshot de destination en HD.
     var destinationImg = $('#snapshot-' + destinationId);
@@ -732,22 +1076,23 @@
     destinationImg.attr('src', destinationImgSrc.replace('snapshots-little/', 'snapshots/'));
     
     //On passe l'ancien snapshot en SD.
-    var currentImgSrc = $('img', mos.previousZoomedSN).attr('src');
-    $('img', mos.previousZoomedSN).attr('src', currentImgSrc.replace('snapshots/', 'snapshots-little/'));
+    var currentImgSrc = $('img', _this.previousZoomedSN).attr('src');
+    $('img', _this.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 neighbourFrame = $(this);
+    var neighbourFrame = neighbour;
     var tab = neighbourFrame.attr('id').split('-');
-    mos.centerId = tab[1];
+    _this.centerId = tab[1];
     $(this).css('opacity', '0');
     neighbourFrame.remove();
     
-	mos.player.widgets[0].freePlayer();
+	_this.player.widgets[0].freePlayer();
 	$('.LdtPlayer').remove();
 	$('body').append('<div class="LdtPlayer" id="LdtPlayer"></div>');
+	_this.reaffectKeyPress();
 	
     //On grise le snapshot qu'on vient de quitter.
-    mos.previousZoomedSN.animate(
+    _this.previousZoomedSN.animate(
     {
         opacity: '0.4'
     });
@@ -757,20 +1102,23 @@
     {
         top: MPCurrentTop,
         left: MPCurrentLeft
-    }, timeMovingToNeighbour, function()
+    }, _this.config['timeMovingToNeighbour'], function()
     {
         //On fait apparaître le snapshot vers lequel on s'est déplacé.
         $('#snapshotDiv-' + destinationId).animate(
         {
             opacity: '1'
-        }, mos.zoomTime, function()
+        }, _this.config['zoomTime'], function()
         {
             //On recharge les voisins.
-            $('.snapshotDivs').unbind('mouseenter', mos.selectNeighbour);
-            mos.previousZoomedSN = $('#snapshotDiv-' + mos.centerId);
-            mos.listenToNeighbours();
+            $('.snapshotDivs').unbind('mouseenter', _this.selectNeighbour);
+            _this.previousZoomedSN = $('#snapshotDiv-' + _this.centerId);
+            _this.listenToNeighbours();
 			
-			mos.loadPlayer((destinationImg.position().top + MPCurrentTop + mos.MPTop_margin), (destinationImg.position().left + MPCurrentLeft), destinationImg.width(), destinationImg.height(), MPCurrentTop, MPCurrentLeft);
+			_this.notifyTopVideo = MPCurrentTop;
+			_this.notifyLeftVideo = MPCurrentLeft;
+			
+			_this.loadPlayer((destinationImg.position().top + MPCurrentTop + _this.MPTop_margin), (destinationImg.position().left + MPCurrentLeft), destinationImg.width(), destinationImg.height(), MPCurrentTop, MPCurrentLeft);
         });
     });
 }
@@ -834,19 +1182,24 @@
 	{
 		$.each(data, function(key, val)
 		{
-			// console.log(val);
 			$.each(val, function(key_video, val_video)
 			{
 				$.getJSON(val_video.metadata, function(meta)
 				{
-					_this.affectVideoById(val_video.metadata, meta.medias[0].url.replace('rtmp://', 'http://').replace('/ddc_player/', '/').replace('mp4:', '').replace('.m4v', '.mp4'));
-					//console.log(meta.medias[0].url.replace('rtmp://', 'http://').replace('/ddc_player/', '/'));
+					if(_this.config['local'] == 'true')
+					{
+						_this.affectVideoById(val_video.metadata, meta.medias[0].url.replace('rtmp://media.iri.centrepompidou.fr/ddc_player/', './player/videos/').replace('mp4:', '').replace('video/', '').replace('ldtplatform/', '').replace('.m4v', '.mp4'));
+						console.log(meta.medias[0].url.replace('rtmp://media.iri.centrepompidou.fr/ddc_player/', './player/videos/').replace('mp4:', '').replace('video/', '').replace('ldtplatform/', '').replace('.m4v', '.mp4'));
+					}
+					else
+					{
+						_this.affectVideoById(val_video.metadata, meta.medias[0].url.replace('rtmp://', 'http://').replace('/ddc_player/', '/').replace('mp4:', '').replace('.m4v', '.mp4'));
+						console.log(meta.medias[0].url.replace('rtmp://', 'http://').replace('/ddc_player/', '/').replace('mp4:', '').replace('.m4v', '.mp4'));
+					}
 				});
-				
-				// _this.imgs.push(val_video.snapshot);
-				// _this.urls.push(val_video.metadata);
 				_this.imgs[_this.ids[i]] = val_video.snapshot;
 				_this.urls[_this.ids[i]] = val_video.metadata;
+				console.log('ids : ' + _this.ids[i]);
 				i++;
 			});
 		});
@@ -921,6 +1274,11 @@
 */
 mosaic.prototype.notifySelectionSearchMosaicFull = function()
 {
+	if(this.currentMode == "NO-USER" || this.currentMode.indexOf("INCOMING") == -1)
+	{
+		return;
+	}
+	
 	//On spécifie les notifications en div.
 	var notification_selection = "<div id='notify_selection' class='notifications'></div>";
 	var notification_search = "<div id='notify_search' class='notifications'></div>";
@@ -964,7 +1322,7 @@
 */
 mosaic.prototype.notifyPointMosaicPrezoom = function()
 {
-	if($('#notify_point').length > 0)
+	if($('#notify_point').length > 0 || this.currentMode == "NO-USER" || this.currentMode.indexOf("INCOMING") == -1)
 	{
 		return;
 	}
@@ -974,7 +1332,7 @@
 	
 	//On les ajoute à la mosaïque.
 	$('#mainPanel').append(notification_point);
-	console.log('Append');
+	
 	//On calcule leurs coordonnées et dimensions.
 	var notify_width = $('.notifications').width(), notify_height = $('.notifications').height();
 	var notify_margin = parseInt($('.notifications').css('margin'));
@@ -1071,8 +1429,7 @@
 		left: "0px",
 		top: "0px",
 		width: notify_width - notify_margin * 2,
-		height: notify_height - notify_margin * 2,
-		"margin-top": notify_margin_top
+		height: notify_height - notify_margin * 2
 	});
 	
 	var search_width = $('#help_search').width();
@@ -1131,4 +1488,220 @@
 		_this.helpDisplayed = false;
 		$('#notify_help').remove();
 	});
+}
+
+/*
+ * Affiche les types de marqueurs correspondants à ce qu'on a commencé à tracer lors d'une recherche.
+*/
+ mosaic.prototype.notifySearchMarkers = function(markersStr)
+{
+	if($('.notifications_inSearch_container').length > 0)
+	{
+		return;
+	}
+	
+	console.log(markersStr);
+	
+	var markersList = markersStr.split(new RegExp(';'));
+	
+	var notification_search_markers = "<div class='notifications_inSearch_container'>";
+	
+	//On spécifie les notifications en div.
+	for(var i = 0 ; i < markersList.length ; i++)
+	{
+		notification_search_markers += "<div class='notifications_inSearch' style='background-image: url(./pictos/big/normal/" + markersList[i] + ".png);'></div>";
+	}
+	
+	notification_search_markers += "</div>";
+	
+	//On les ajoute à la mosaïque.
+	$('#mainPanel').append(notification_search_markers);
+	
+	//On calcule leurs coordonnées et dimensions.
+	var notify_width = $('.notifications_inSearch_container').width(), notify_height = $('.notifications_inSearch_container').height();
+	var notify_margin = parseInt($('.notifications_inSearch').css('margin'));
+	var point_left = $(window).width() / 2 - (notify_width) / 2 - notify_margin;
+	var point_top = 0;
+	
+	if(this.currentMode == "VIDEO" || this.currentMode == "SEARCH")
+	{
+		point_top = -this.notifyTopVideo,
+		point_left = -this.notifyLeftVideo + ($(window).width() - notify_width) / 2
+	}
+	
+	//On les positionne.
+	$('.notifications_inSearch_container').css(
+	{
+		left: point_left,
+		top: point_top
+	});
+	
+	//On les fait apparaître.
+	$('.notifications_inSearch').css(
+	{
+		opacity: "0.9"
+	});
+}
+
+/*
+ * Supprime la notification de maintient du pointage.
+*/
+mosaic.prototype.removeSearchMarkers = function()
+{	
+	$('.notifications_inSearch_container').remove();
+}
+
+/*
+ * Effectuer un filtrage de la mosaïque par rapport à un type de marqueurs.
+*/
+mosaic.prototype.searchFilter = function(type)
+{
+	var _this = this;
+	
+	if(this.currentMode == "MOSAIC")
+	{
+		this.currentMode = "FILTER";
+		
+		if(this.annotations.length > 0)
+		{
+			var gestureNumberByVideo = new Object();
+			var maxAnnotationNumber = 0;
+			// for(var i = 0 ; i < this.config['imagesToShow'] ; i++)
+			for(var i = 0 ; i < this.annotations.length ; i++)
+			{
+				var current = this.annotations[i];
+				if(current.annotationType.contents.title == type)
+				{
+					if(gestureNumberByVideo[current.source.url] == undefined || gestureNumberByVideo[current.source.url] == '')
+					{
+						gestureNumberByVideo[current.source.url] = 0;
+					}
+					
+					gestureNumberByVideo[current.source.url]++;
+				}
+			}
+			
+			for(var i = 0 ; i < this.urls.length ; i++)
+			{
+				if(gestureNumberByVideo[this.urls[i]] == undefined || gestureNumberByVideo[this.urls[i]] == '')
+				{
+					gestureNumberByVideo[this.urls[i]] = 0;
+				}
+			}
+			
+			//On récupère la vidéo qui score le nombre d'occurences de la gesture le plus haut.
+			for(i in gestureNumberByVideo)
+			{	
+				// console.log(i + " " + gestureNumberByVideo[i]);
+				if(maxAnnotationNumber < gestureNumberByVideo[i])
+				{
+					maxAnnotationNumber = gestureNumberByVideo[i];
+				}
+			}
+			
+			var snMargin = parseInt($('.snapshotDivs').css('margin'));
+			
+			//On affiche l'opacité résultante pour chaque vidéo.
+			for(i in gestureNumberByVideo)
+			{
+				//Opacité conventionelle.
+				var opacity = gestureNumberByVideo[i] / maxAnnotationNumber;
+				// console.log('opacity b : ' + opacity + ' for ' + gestureNumberByVideo[i]);
+				//Ce qui est à zéro le restera (par conséquent le snapshot associé sera invisible).
+				if(opacity > 0)
+				{
+					//On réhausse l'opacité de 50%.
+					opacity = this.scaleIntervals(0., 1., 0.5, 1., opacity);
+				}
+				
+				var filterIndex = this.getIdxFromMetadata(i);
+				
+				if(filterIndex >= 0)
+				{
+					console.log('#snapshotDiv-' + filterIndex + " " + _this.config['timeFilterFade'] + " " + opacity);
+					$('#snapshotDiv-' + filterIndex).fadeTo(_this.config['timeFilterFade'], opacity);
+					
+					if(opacity == 0)
+					{
+						var filteredSnapshot = $('#snapshotDiv-' + filterIndex);
+						
+						if(filteredSnapshot.length > 0)
+						{
+							var hider = '<div id="filterHider-' + filterIndex + '" class="filterHiders"></div>';
+							$('#mainPanel').append(hider);
+							
+							$('#filterHider-' + filterIndex).css(
+							{
+								width: +filteredSnapshot.width() + 4 * snMargin,
+								height: +filteredSnapshot.height() + 4 * snMargin,
+								top: filteredSnapshot.position().top - snMargin,
+								left: filteredSnapshot.position().left - snMargin
+							});
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Passe une valeur de l'intervalle [A, B] à l'intervalle [C, D].
+*/
+mosaic.prototype.scaleIntervals = function(A, B, C, D, val)
+{
+	return (D - C + A) * val + (C - A);
+}
+
+/*
+ * Retourne l'index d'un snapshot en fonction de ses metadonnées.
+*/
+mosaic.prototype.getIdxFromMetadata = function(metadata)
+{
+	var _this = this;
+	
+	for(idx in this.urls)
+	{
+		if(this.urls[idx] == metadata)
+		{
+			for(id in this.ids)
+			{
+				if(this.ids[id] == idx)
+				{
+					return id;
+				}
+			}
+		}
+	}
+	
+	return -1;
+}
+
+/*
+ * Enlève une recherche par filtre.
+*/
+mosaic.prototype.removeFilter = function()
+{
+	if(this.currentMode == "FILTER")
+	{
+		this.currentMode = "MOSAIC";
+		
+		var _this = this;
+		
+		$('.filterHiders').remove();
+		$('.snapshotDivs').fadeTo(_this.config['timeFilterFade'], 1);
+	}
+}
+
+/*
+ * Rebind keypress pour body.
+*/
+mosaic.prototype.reaffectKeyPress = function()
+{
+	var _this = this;
+	
+	$('body').keypress(function (event)
+	{
+		_this.manageControlEvents(event);
+	});
 }
\ No newline at end of file