/*
* 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(config, default_conf)
{
//Interactions souris/kinect.
this.mouseInteractions = true;
//Interactions avec/sans préphase.
this.prephaseEnabled = true;
this.gestures = ["fall", "jump", "circle", "screw", "bend", "arc", "pendulum", "knee-up", "right-angle", "wave", "slow", "hello", "no-motion", "wheel", "contact", "run", "up-down", "grand-jete"];
//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.sources = [];
this.imgs = [];
this.opacities = [];
this.timeToGoAt = [];
this.ids = [];
this.fillingIds = [];
this.currentRandomVideoIdx = 0;
//Dictionnaire pour les courbes de recherche.
this.dictionary = [];
//Dernières positions des pointeurs.
this.mainPointerLastX;
this.mainPointerLastY;
this.secondPointerLastX;
this.secondPointerLastY;
//Dernières positions avant le lancement de la fonction d'idle.
this.mainPointerIdleStartX;
this.mainPointerIdleStartY;
this.secondPointerIdleStartX;
this.secondPointerIdleStartY;
//Coordonnées de la souris dans le mode d'interaction souris.
this.mousePosX;
this.mousePosY;
//Coordonnées précédentes de la souris dans le mode d'interaction souris.
this.mousePosLastX;
this.mousePosLastY;
//Valeur du déplacement entre un mouse up et un mouse down.
this.mouseUpDownDelta = 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 = false;
this.fullscreen = false;
this.canMoveToNeighbour = false;
this.mainPointerExitBorder = false;
this.secondPointerExitBorder = false;
this.isMainPointerDisplayed = false;
this.isSecondPointerDisplayed = false;
this.helpDisplayed = false;
//Indique si l'utilisateur a manuellement pausé la vidéo.
this.userPaused = false;
//Indique si on est en train de se déplacer vers un voisin.
this.currentlyMoving = false;
//Indique si on est en train de dézoomer vers la mosaïque.
this.currentlyUnzooming = false;
//Indique si on peut s'approcher de kinect.
this.canStart = false;
//Indique si on est actuellement sur un snapshot.
this.isOnASnapshot = false;
//Indique si l'idle des pointeurs est disponible (deux mains détectées).
this.pointersIdleAvailable = false;
//Indique si le timeout pour l'idle des pointeurs à besoin d'être lancé.
this.pointersIdleNeedLaunch = false;
//Indique si les deux mains sont là.
this.areBothPointersHere = false;
//Indique si le timeout pour la détection de deux pointeurs a été lancé.
this.areBothPointersTimeoutLaunched = false;
//Indique si la mosaïque a été filtrée.
this.isMosaicFiltered = false;
//Indique si on est actuellement dans une recherche par gesture.
this.isCurrentlyInASearchByGesture = false;
//Indique si un pointeur est déjà sur une notification de recherche par gesture.
this.alreadyOnNotification = false;
//Si on a fait un swipe.
this.isSwipe = false;
//On peut swiper.
this.canSwipe = false;
//On passe vers une autre video automatiquement à la fin d'une lecture.
this.autoMove = false;
//Si l'utilisateur a demandé à sélectionner la TL.
this.isTLRequested = false;
//Le pointeur gauche a sélectionné la TL.
this.isTLSelectedBySecondPointer = false;
//Le pointeur droit a sélectionné la TL.
this.isTLSelectedByMainPointer = false;
//On peut afficher l'aide.
this.canNotifyHelp = false;
//Indique si la mosaique est en train d'être filtrée.
this.isMosaicFiltering = false;
this.arrowLeftLoading = false;
this.arrowRightLoading = false;
this.arrowUpLoading = false;
this.arrowDownLoading = false;
//On est dans une recherche par courbes.
this.isSearchByCurvesOn = false;
this.canDrawNextCurve = false;
//Dans le mode d'interaction souris, indique si on se situe actuellement sur un snapshot entièrement prézoomé.
this.isOnAPrezoomSN = false;
//Indique si une courbe de recherche donne au moins un résultat.
this.curvesGesturesFound = false;
//Indique si on souhaite supprimer la recherche en cours.
this.gestureDelRequested = false;
//Code de gesture actuellement calculé par les détecteurs de courbes.
this.actualCode = '';
//Indique si l'utilisateur est entré dans la zone de recherche.
this.isUserInSearchZone = false;
//Timeout (attente) pour le zoom après un préZoom.
this.zoomTimeout = null;
//Timeout (attente) pour le passage vers un voisin.
this.moveToNeighbourTimeout = null;
this.mainPointerExitBorderTimeout = null;
this.secondPointerExitBorderTimeout = null;
//Idle time pour les pointeurs afin d'informer le front qu'on souhaite faire une recherche.
this.pointersSearchIdleTimeout = null;
//Vérifie toutes les N ms que les deux pointeurs sont détectés.
this.areBothPointersHereTimeout = null;
//Délai de suppression d'une notification de recherche par gesture.
this.removeNotificationByGestureTimeout = null;
//Délai de suppression d'une notification de recherche par gesture infructueuse.
this.removeFailedNotificationByGestureTimeout = null;
//Délai avant la suppression de notification swipe.
this.notifySwipeTimeout = null;
//Délai pour la sélection de la TL.
this.selectTLTimeout = null;
//Délai pour slider sur la TL.
this.canSlideInTLTimeout = null;
//Délai pour afficher l'aide.
this.canNotifyHelpTimeout = null;
this.arrowLeftTimeout = null;
this.arrowRightTimeout = null;
this.arrowUpTimeout = null;
this.arrowDownTimeout = null;
this.arrowSpinnerTimeout = null;
this.nouserTimeout = null;
this.nextDrawCurveTimeout = null;
//Dernier message INCOMING (pour éviter d'effectuer n fois la même action.
this.lastIncomingMessage = '';
//Type de marqueur recherché dans la mosaïque (en mode filter).
this.filterSearchedType = "";
//Mode actuel.
this.currentMode = "NO-USER";
//Snapshot sur lequel on a zoomé.
this.previousZoomedSN = null;
//Snapshot sur lequel on a prezoomé.
this.previousPrezoomDiv = null;
//Son ID.
this.previousId = null;
//Dernier snapshot prézoomé non null.
this.lastNonNullSN = null;
//Largeur de la marge pour le centrage vertical de la mosaïque.
this.MPTop_margin;
this.top_margin;
//Gestures actuellement cherchées dans les vidéos.
this.currentSearchGesture = [];
//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;
//Voisins sélectionnés par les pointeurs.
this.mainPointerNeighbourSelectedId = null;
this.secondPointerNeighbourSelectedId = null;
//Snapshots a afficher.
this.snapshotsToShow = 1;
//Lecteur.
this.player = null;
//Si le lecteur est prêt.
this.playerIsReady = false;
//Annotations (pour les marqueurs los d'un filtrage).
this.annotations = [];
//Client websocket pour recevoir les notifications du Middleware.
this.client;
//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);
}
/*
* Méthode d'affichage de la mosaïque.
* Génère une matrice de imgs.
*/
mosaic.prototype.createMosaic = function()
{
// 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)
{
this.lastIncomingMessage = 'INCOMING-0';
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>';
//Au départ aucune vidéo n'a de gesture de recherche.
this.currentSearchGesture[i] = '';
}
}
return str + '<div id="ghostPanel"></div>';
}
else
{
alert("Le nombre d'images a afficher doit être divisible par la longueur de la mosaïque !");
}
}
/*
* Permet de raffraichir la mosaïque.
*/
mosaic.prototype.loadMosaic = function()
{
// console.log('LOAD');
var createMosaic = this.createMosaic();
if(createMosaic == '')
{
return;
}
var _this = this;
//On affecte les chemins vers les images à la mosaïque.
this.previousZoomedSN;
//this.width =
// console.log(createMosaic);
//On met à jour la mosaïque.
$('#mainPanel').html(createMosaic);
//On récupère la taille des bordures.
this.marginWidth = $('.snapshotDivs').css('margin-bottom');
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.config['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);
//On fait coincider le background du body avec celui de la mosaïque.
$('body').css('background-position', '0px ' + this.MPTop_margin + 'px');
/*$('.snapshotDivs').mouseover(function ()
{
//On effectue un prézoom dès qu'on va sur une image.
_this.preZoom($(this));
});*/
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]);
_this.sources[i] = sourceManager.remoteSource({url: _this.urls[i], serializer: IriSP.serializers.ldt});
_this.sources[i].onLoad(function()
{
var source = this;
// console.log(source);
globalAnnotations.addElements(source.getAnnotations());
// console.log(source.url + ' ' + source.getAnnotations().length);
fichiersCharges++;
if (fichiersCharges == nbFichiers)
{
// instructions à exécuter quand tout est chargé
_this.annotations = globalAnnotations;
// console.log(_this.annotations.length + ' ' + nbFichiers);
console.log(_this.annotations.length + ' annotations loaded from ' + nbFichiers + ' files.');
//Si on gère les interactions à la souris.
if(_this.mouseInteractions)
{
$(window).mousemove(function(e)
{
_this.refreshMainPointer(e.pageX, e.pageY, _this);
_this.mousePosX = e.pageX;
_this.mousePosY = e.pageY;
});
}
if(_this.prephaseEnabled && !_this.mouseInteractions)
{
_this.init();
_this.showNImages(0);
_this.currentMode = "NO-USER";
}
else
{
_this.showNImages(20);
_this.currentMode = "MOSAIC";
}
// /!\ //
// _this.currentMode = "FILTER";
// _this.showNImages(20);
//_this.isSearchByCurvesOn = true;
// _this.startSearch();
// console.log('CANVAS READY');
// /!\ //
_this.previousZoomedSN = $('#snapshotDiv-' + _this.fillingIds[0]);
}
});
}
if(this.mouseInteractions)
{
//Si on fait un mouse down sur le body, on vérifie enregistre le déplacement de la souris jusqu'au prochain mouse up.
$(window).mousedown(function (e)
{
_this.removeSearchNotificationIfOnIt(e.pageX, e.pageY);
_this.isUserInSearchZone = true;
if(_this.isSearchByCurvesOn)
{
_this.searchCanvas.onPointerIn(_this.mousePosX, _this.mousePosY, null, null);
}
console.log('mdown');
//On écoute le déplacement de la souris.
$(window).mousemove(function(e)
{
if(_this.isSearchByCurvesOn)
{
_this.searchCanvas.onPointerMove(_this.mousePosX, _this.mousePosY - _this.MPTop_margin, null, null);
}
//On met à jour l'ancienne position de la souris si elle est nulle.
if(!_this.mousePosLastX && _this.mousePosLastX != 0)
{
_this.mousePosLastX = _this.mousePosX;
}
if(!_this.mousePosLastY && _this.mousePosLastY != 0)
{
_this.mousePosLastY = _this.mousePosY;
}
//Le delta s'accroît si la souris bouge.
_this.mouseUpDownDelta += Math.floor(Math.sqrt((_this.mousePosLastX - e.pageX) * (_this.mousePosLastX - e.pageX) + (_this.mousePosLastY - e.pageY) * (_this.mousePosLastY - e.pageY)));
// console.log(_this.mouseUpDownDelta, _this.mousePosLastX, e.pageX);
if(_this.mousePosLastX != _this.mousePosX)
{
_this.mousePosLastX = _this.mousePosX;
}
if(_this.mousePosLastY != _this.mousePosY)
{
_this.mousePosLastY = _this.mousePosY;
}
//Si la souris a parcouru une trop grande distance, on entre en recherche.
if(_this.mouseUpDownDelta > _this.config['mouseUpDownDeltaTreshold'])
{
//Si on est en mosaique, on entre en filtrage.
if(_this.currentMode == "MOSAIC")
{
_this.preUnzoom();
_this.currentMode = "FILTER";
_this.isMosaicFiltered = true;
console.log(_this.date() + ' - ENTRE EN MODE FILTRAGE');
_this.isSearchByCurvesOn = true;
_this.startSearch();
/*if(!_this.curvesGesturesFound)
{
this.removeNotifications();
_this.filterSearch();
}*/
_this.searchCanvas.onPointerIn(_this.mousePosX, _this.mousePosY - _this.MPTop_margin, null, null);
}
else if(_this.currentMode == "FILTER" && !_this.isSearchByCurvesOn && _this.isUserInSearchZone)
{
console.log('after search');
_this.preUnzoom();
_this.isSearchByCurvesOn = true;
_this.startSearch();
_this.searchCanvas.onPointerIn(_this.mousePosX, _this.mousePosY - _this.MPTop_margin, null, null);
}
//Si on est dans une vidéo, on entre en recherche.
else if(_this.currentMode == "VIDEO" || _this.currentMode == "TIMELINE")
{
_this.currentMode = "SEARCH";
console.log(_this.date() + ' - ENTRE EN MODE RECHERCHE');
_this.isSearchByCurvesOn = true;
_this.startSearch();
/*if(!_this.curvesGesturesFound)
{
this.removeNotifications();
_this.searchSearch();
}*/
_this.searchCanvas.onPointerIn(_this.mousePosX, _this.mousePosY - _this.MPTop_margin, null, null);
}
else if(_this.currentMode == "SEARCH" && !_this.isSearchByCurvesOn)
{
_this.isSearchByCurvesOn = true;
_this.startSearch();
_this.searchCanvas.onPointerIn(_this.mousePosX, _this.mousePosY - _this.MPTop_margin, null, null);
}
//Il est possible d'afficher l'aide.
if(!_this.canNotifyHelp)
{
_this.canNotifyHelpTimeout = setTimeout(function()
{
_this.canNotifyHelp = true;
}, _this.config['timeoutCanNotifyHelp']);
}
}
});
//Si on fait un mouse up après ce mouse down.
$(window).mouseup(function()
{
console.log('mup');
if(_this.isSearchByCurvesOn)
{
_this.isUserInSearchZone = false;
var gesture_match = _this.gestureWithSameCode(_this.actualCode);
_this.actualCode = '';
if(gesture_match.length > 0)
{
if(_this.currentMode == "SEARCH" && _this.playerIsReady)
{
_this.player.widgets[0].searchByGesture(gesture_match);
_this.isCurrentlyInASearchByGesture = _this.player.widgets[0].isCurrentlyInASearchByGesture;
if(_this.player && _this.player.widgets[0] && _this.timeToGoAt[_this.centerId] === 0 && _this.player.widgets[0].atLeastOneSearchMarker(_this.currentSearchGesture[_this.centerId]))
{
_this.player.widgets[0].goToFirstSearchedMarker(_this.currentSearchGesture[_this.centerId]);
}
_this.removeNotifications();
_this.currentSearchGesture[_this.centerId] = gesture_match;
_this.searchGesture(gesture_match, 'valid');
_this.curvesGesturesFound = false;
}
else if(_this.currentMode == "FILTER")
{
if(_this.isMosaicFiltered)
{
_this.removeNotifications();
_this.filterSearchedType = gesture_match;
_this.filterGesture(gesture_match, 'valid');
_this.searchFilter(gesture_match);
_this.curvesGesturesFound = false;
}
}
}
_this.searchCanvas.onPointerOut();
}
//On unbind ce qui a été bindé après le mouse up.
$(window).unbind('mousemove');
$(window).unbind('mouseup');
//On rebind le mousemove principal du body, car ils ont tous été unbindés.
$(window).mousemove(function(e)
{
_this.refreshMainPointer(e.pageX, e.pageY, _this);
_this.mousePosX = e.pageX;
_this.mousePosY = e.pageY;
});
_this.mousePosLastX = null;
_this.mousePosLastY = null;
//Si la distance parcourue par la souris entre le mouse down et le mouse up est inférieure ou égale au seuil.
if(_this.mouseUpDownDelta <= _this.config['mouseUpDownDeltaTreshold'])
{
//Si on est sur un snapshot prézoomé.
if(_this.isOnAPrezoomSN && _this.previousZoomedSN != '' && (_this.currentMode == 'MOSAIC' || _this.currentMode == 'FILTER'))
{
_this.zoom();
}
}
_this.mouseUpDownDelta = 0;
_this.isSearchByCurvesOn = false;
_this.leaveSearch();
if(_this.currentMode == 'FILTER' && _this.filterSearchedType != '')
{
_this.removeNotifications();
_this.filterGesture(_this.filterSearchedType, 'valid');
}
});
});
}
}
/*
* 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', 'zoomTime', 'timeUnzoom', 'timeNeighbourGlowing', 'timeNeighbourUnglowing', 'timeMovingToNeighbour', 'timeSearchFade', 'timeNotifyFade', 'timeFilterFade', 'timeANFade', 'timeFilling', 'zoomedMargin', 'timeoutZoom', 'timeoutUnzoom', 'timeoutMoveToNeighbour', 'timeoutPointersIdle', 'timeoutAreBothPointersHere', 'timeoutRemoveNotificationByGesture', 'timeoutRemoveFailedNotificationByGesture', 'timeoutNotifySwipe', 'timeoutSelectTL', 'timeoutSlideTL', 'timeoutCanNotifyHelp', 'timeoutRemoveSpinner', 'timeoutNouser', 'timeoutNextDrawCurve', 'mouseUpDownDeltaTreshold'];
var supposedToBeFloat = ['zoomPercentage', 'prezoomPercentage'];
$.getJSON(file_path, function(data)
{
for(key in data)
{
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');
}
//On initialise le client.
if(!_this.mouseInteractions)
{
_this.client = new client(_this.config['host'], _this.config['port'], _this);
}
_this.getDictionary();
_this.getLang();
});
}
/*
* 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('CURRENT MODE : ' + _this.currentMode);
// console.log('ids', this.fillingIds[this.currentRandomVideoIdx]);
this.previousZoomedSN.fadeTo(this.config['timePrezoom'], 1, function()
{
// console.log('CURRENT MODE : ' + _this.currentMode);
_this.zoom();
_this.currentRandomVideoIdx++;
});
}
/*
* Remplissage de la mosaïque en fonction du nombre d'images à afficher.
*/
mosaic.prototype.showNImages = function(n)
{
if(this.currentlyMoving)
{
return;
}
// console.log('INCOMING ----- ' + n);
//Si il y a plus d'un snapshot à afficher, on entre dans le mode INCOMING avec en paramètre le nombre à afficher.
if(n > 1 && n < this.config['imagesToShow'])
{
this.currentMode = "INCOMING-" + n;
this.unzoom();
for(var i = 0 ; i < this.config['imagesToShow'] ; i++)
{
this.currentSearchGesture[i] = '';
}
this.removeNotifications();
this.isMosaicFiltered = false;
this.isCurrentlyInASearchByGesture = false;
$('#mainPointer').fadeTo(this.config['timePrezoom'], 0);
$('#secondPointer').fadeTo(this.config['timePrezoom'], 0);
$('#spinner').remove();
this.deselectAllNeighbours();
$('.prezoomContainers').remove();
}
// console.log('n : ' + n);
if(n >= this.config['imagesToShow'])
{
// this.unzoom();
if(this.currentMode == "NO-USER" || this.currentMode.indexOf("INCOMING-") > -1)
{
if(!this.mouseInteractions)
{
this.currentMode = "INCOMING-20";
this.unzoom();
}
this.currentMode = "MOSAIC";
this.removeNotifications();
this.mosaicSelectionAndSearch();
clearTimeout(this.nouserTimeout);
console.log('OK');
}
//On affiche les notifications.
// this.notifySelectionSearchMosaicFull();
//$('#mainPointer').fadeTo(this.config['timePrezoom'], 1);
//$('#secondPointer').fadeTo(this.config['timePrezoom'], 1);
}
//Pour les snapshots à afficher.
for(var i = 0 ; i < n ; i++)
{
//Si les snapshots ne sont pas affichés.
if($('#snapshotDiv-' + this.fillingIds[i]).css('opacity') < 1)
{
//On les fait apparaître.
$('#snapshotDiv-' + this.fillingIds[i]).fadeTo(this.config['timeFilling'], '1');
}
}
//Pour ceux à masquer.
for(var i = n ; i < this.config['imagesToShow'] ; i++)
{
//Si les snapshots ne sont pas masqués et qu'il ne s'agit pas du dernier snapshot en lecture aléatoire (mode NO-USER).
if($('#snapshotDiv-' + this.fillingIds[i]).css('opacity') > 0 && this.fillingIds[i] != this.currentRandomVideoIdx)
{
//On les masque.
$('#snapshotDiv-' + this.fillingIds[i]).fadeTo(this.config['timeFilling'], '0');
}
}
}
/*
* Gère les événements de contrôle dans la mosaïque.
*/
mosaic.prototype.manageControlEvents = function(event)
{
// console.log('manage');
var _this = this;
if(typeof event === 'undefined')
{
return;
}
var gestureReceived = '';
if(event.indexOf("INCOMING-") != -1 && this.prephaseEnabled)
{
// console.log(this.date() + ' ' + event);
// console.log('CAN START : ' + this.canStart);
if(this.canStart)
{
if(this.snapshotsToShow > this.config['imagesToShow'])
{
this.snapshotsToShow = this.config['imagesToShow'];
}
else
{
var params = event.split('-');
// console.log(event);
this.snapshotsToShow = params[1];
}
//Si la position de l'utilisateur a changé.
if(event != this.lastIncomingMessage)
{
console.log(this.snapshotsToShow);
this.lastIncomingMessage = event;
this.showNImages(this.snapshotsToShow);
}
}
clearTimeout(this.nouserTimeout);
this.nouserTimeout = setTimeout(function()
{
/*_this.showNImages(0);
_this.init();
_this.canStart = false;
_this.currentMode = "NO-USER";*/
window.location.reload();
// mos = new mosaic('./config.json', default_parameters);
console.log('NOUSER');
}, this.config['timeoutNouser']);
}
else if((event == "NO-USER" || event == "INCOMING-0" || event == "INCOMING-1") && this.prephaseEnabled)
{
/*this.showNImages(0);
this.init();
this.canStart = false;
this.currentMode = "NO-USER";*/
window.location.reload();
// mos = new mosaic('./config.json', default_parameters);
console.log('NOUSER');
/*this.currentMode = "NO-USER";
this.showNImages(0);
this.canStart = false;
this.init();*/
}
// /!\/!\ //
else if(event.indexOf("SWIPE") != -1)
{
if(this.player && this.player.widgets && this.playerIsReady && !this.isSwipe)
{
this.isSwipe = true;
if(this.currentMode == 'SEARCH' && this.isMosaicFiltered && !this.player.widgets[0].isAMarkerAhead(this.currentSearchGesture[this.centerId]))
{
this.playNextVideo();
}
//L'utilisateur a fait un swipe left.
if(event.indexOf("LEFT") != -1)
{
this.player.widgets[0].switchToMarker(true, this.currentSearchGesture[this.centerId]);
if(this.currentMode == 'VIDEO')
{
this.removeNotifications();
this.videoSwipe('left');
}
else if(this.currentMode == 'SEARCH' && !this.currentSearchGesture[this.centerId])
{
this.removeNotifications();
this.searchSearchAndSwipe('left');
}
else if(this.currentMode == 'SEARCH' && this.currentSearchGesture[this.centerId])
{
this.removeNotifications();
this.searchGestureAndSwipe(this.currentSearchGesture[this.centerId], 'valid', 'left');
}
}
//L'utilisateur a fait un swipe right.
else if(event.indexOf("RIGHT") != -1)
{
this.player.widgets[0].switchToMarker(false, this.currentSearchGesture[this.centerId]);
if(this.currentMode == 'VIDEO')
{
this.removeNotifications();
this.videoSwipe('right');
}
else if(this.currentMode == 'SEARCH' && !this.currentSearchGesture[this.centerId])
{
this.removeNotifications();
this.searchSearchAndSwipe('right');
}
else if(this.currentMode == 'SEARCH' && this.currentSearchGesture[this.centerId])
{
this.removeNotifications();
this.searchGestureAndSwipe(this.currentSearchGesture[this.centerId], 'valid', 'right');
}
}
//On le fait disparaitre au bout d'un certain temps.
this.notifySwipeTimeout = setTimeout(function()
{
_this.isSwipe = false;
// /!\ //
_this.removeNotifications();
if(_this.currentMode == 'SEARCH' && !_this.currentSearchGesture[_this.centerId])
{
_this.searchSearch();
}
else if(_this.currentMode == 'SEARCH' && _this.currentSearchGesture[_this.centerId])
{
_this.searchGesture(_this.currentSearchGesture[_this.centerId], 'valid');
}
}, this.config['timeoutNotifySwipe']);
}
}
else if(event.indexOf("BEND") != -1 || event.indexOf('KNEE-UP') != -1 || event.indexOf('FALL') != -1 || event.indexOf('JUMP') != -1)
{
gestureReceived = event.toLowerCase();
gestureReceived = gestureReceived.replace('wave', 'hello');
this.currentSearchGesture[centerId] = gestureReceived;
}
else if(event.indexOf("HELLO") != -1 && this.canNotifyHelp && !this.areBothPointersHere)
{
if(this.currentMode == 'SEARCH')
{
this.notifyHelp(false);
}
else if(this.currentMode == 'FILTER')
{
this.notifyHelp(true);
}
}
if(gestureReceived != '')
{
if(this.currentMode == "SEARCH" && this.playerIsReady)
{
this.player.widgets[0].searchByGesture(gestureReceived);
this.isCurrentlyInASearchByGesture = this.player.widgets[0].isCurrentlyInASearchByGesture;
this.removeNotifications();
this.searchGesture(gestureReceived, 'valid');
}
else if(this.currentMode == "FILTER")
{
if(this.isMosaicFiltered)
{
// console.log('FILTER !!!');
// this.notifySearch1Gesture(gestureReceived, 'valid');
this.removeNotifications();
this.filterGesture(gestureReceived, 'valid');
this.searchFilter(gestureReceived);
}
}
if(this.helpDisplayed)
{
this.removeHelp();
}
}
// /!\/!\ //
}
/*
* Chargement du player basé sur le metadataplayer.
*/
mosaic.prototype.loadPlayer = function(newZoomTop, newZoomLeft, newSnWidth, newSnHeight, zoomTop, zoomLeft, timeToGo)
{
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];
var _metadata = {
url: currentMetadata,
format: 'ldt'
};
var _config = {
gui: {
zoomTop: zoomTop - this.marginWidth*2,
zoomLeft: zoomLeft,
width: newSnWidth,
height: newSnHeight,
container: 'LdtPlayer',
default_options: {
metadata: _metadata
},
css:'./player/metadataplayer/LdtPlayer-core.css',
widgets: [
{
type: "Timeline"
}
]
},
player:{
type: 'html5', // player type
video: videoToPlay,
live: true,
height: newSnHeight,
width: newSnWidth,
autostart: true
}
};
//On positionne le player.
$('.LdtPlayer').css(
{
//display: 'none',
position: 'absolute',
'background-color': '#000000',
top: newZoomTop,
left: newZoomLeft
});
//On démarre le player.
this.player = null;
this.player = new IriSP.Metadataplayer(_config, _metadata);
this.player.onLoad(function()
{
if(_this.currentMode == 'NO-USER')
{
//On peut s'approcher de la kinect.
_this.canStart = true;
console.log('CAN START !');
// 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)
{
_this.player.popcorn.listen('pause', function()
{
//Si l'utilisateur a mis en pause.
if(_this.userPaused)
{
}
//Si la pause est naturelle (fin de la timeline, dézoom, déplacement vers un voisin).
else
{
//Si c'est en mode sans utilisateur.
if(_this.currentMode == 'NO-USER')
{
//On dézoome.
_this.unzoom();
}
//Sinon.
else
{
//Si ce n'est pas causé par un déplacement ou un dézoom.
if(!_this.currentlyMoving && !_this.currentlyUnzooming)
{
//On réinitialise la position du curseur à la prochaine lecture de la vidéo.
console.log('REINIT');
//On passe a la video suivante.
console.log('AUTOMOVE');
//Si on est en mode timeline et qu'on est en pause, c'est probablement que l'user a placé le curseur à la fin.
if(_this.currentMode != 'TIMELINE')
{
_this.playNextVideo();
}
//_this.timeToGoAt[parseInt(_this.centerId)] = 0;
console.log('time to go at to 0');
// return;
}
}
}
});
// console.log('mosaic filtered : ' + _this.isMosaicFiltered);
_this.player.popcorn.on("markersready", function()
{
_this.playerIsReady = true;
if(_this.player.widgets[0])
{
_this.player.widgets[0].setMouseInteractions(_this.mouseInteractions);
if(_this.gesturesText.length > 0)
{
_this.player.widgets[0].setLang(_this.gesturesText);
}
}
if(_this.currentMode == 'VIDEO' || _this.currentMode == 'SEARCH' || _this.currentMode == 'TIMELINE')
{
_this.canSwipe = true;
}
console.log('TIME TO GO AT : ' + _this.timeToGoAt[_this.centerId], _this.centerId, _this.imgs[_this.centerId]);
// if(_this.isMosaicFiltered)
// {
if(_this.currentSearchGesture[_this.centerId] == '')
{
_this.removeFilter();
}
else
{
_this.currentMode = 'SEARCH';
// console.log(_this.currentSearchGesture);
_this.player.widgets[0].searchByGesture(_this.currentSearchGesture[_this.centerId]);
_this.isCurrentlyInASearchByGesture = _this.player.widgets[0].isCurrentlyInASearchByGesture;
if(_this.timeToGoAt[_this.centerId] === 0 && _this.player.widgets[0].atLeastOneSearchMarker(_this.currentSearchGesture[_this.centerId]))
{
_this.player.widgets[0].goToFirstSearchedMarker(_this.currentSearchGesture[_this.centerId]);
}
else
{
_this.player.popcorn.currentTime(_this.timeToGoAt[_this.centerId]);
}
}
// }
// /!\ //
/*else
{
if(_this.player.popcorn)
{
_this.player.popcorn.currentTime(_this.timeToGoAt[_this.centerId]);
}
}*/
});
}
});
}
/*
* 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;
}
/*
* Charge les vidéos, les snapshots et les annotations depuis un fichier json.
*/
mosaic.prototype.loadFromJson = function(path)
{
var _this = this;
var i = 0;
$.getJSON(path, function(data)
{
$.each(data, function(key, val)
{
$.each(val, function(key_video, val_video)
{
$.getJSON(val_video.metadata, function(meta)
{
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[_this.ids[i]] = val_video.snapshot;
_this.urls[_this.ids[i]] = val_video.metadata;
//Au départ, on commence à 0 ms dans les vidéos.
_this.timeToGoAt[_this.ids[i]] = 0;
// console.log('ids : ' + _this.ids[i]);
i++;
});
});
// console.log('rdy');
_this.loadMosaic();
});
}
/*
* Affecte une vidéo au tableau des vidéos selon son id
*/
mosaic.prototype.affectVideoById = function(metadata_id, video)
{
for (i = 0 ; i < this.urls.length ; i++)
{
if(this.urls[i] == metadata_id)
{
this.videos[i] = video;
break;
}
}
}
/*
* Rebind keypress pour body.
*/
mosaic.prototype.reaffectKeyPress = function()
{
var _this = this;
$('body').keypress(function (event)
{
_this.manageControlEvents(event);
});
}
mosaic.prototype.date = function()
{
var date, h, min, s;
date = new Date();
h = date.getHours();
min = date.getMinutes();
s = date.getSeconds();
if (h < 10)
h = "0" + h;
if (min < 10)
min = "0" + min;
if (s < 10)
s = "0" + s;
return (h + ":" + min + ":" + s);
};