/*
* 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 : Timeline.js
*
* Auteur : alexandre.bastien@iri.centrepompidou.fr
*
* Fonctionnalités : Widget de la timeline du player incorporé dans le Front.
*/
/*
The Timeline Widget fits right under the video
* Est appelé dans les fichiers créant les widgets du metadataplayer.
*/
IriSP.Widgets.Timeline = function(player, config) {
IriSP.Widgets.Widget.call(this, player, config);
this.bindPopcorn("timeupdate","onTimeupdate");
this.bindPopcorn("loadedmetadata","ready");
this.bindPopcorn("markersready","onMarkersReady");
this.timelineSelected = false;
this.markerShowTime = 200;
this.markerLastTime = 5000;
this.markerBigShown = false;
this.currentMarkerIdx = -1;
this.previousMarkerIdx = -1;
this.hideTimeout;
this.currentMode = "VIDEO";
this.paused = false
this.top_epsilon = 0;
this.imgDir = "player/img/";
this.markersDir = "pictos/small/";
this.player = player;
this.isCurrentlyInASearchByGesture = false;
this.mouseInteractions = false;
//Id du marqueur enregistré.
this.currentMarkerId;
//Gestures et noms par défaut.
this.gestures = ["fall", "jump", "circle", "screw", "bend", "arc", "knee-up", "right-angle", "wave", "no-motion", "contact", "up-down"];
this.gesturesText = ["chute", "saut", "rotation", "rotation de groupe", "inclinaison", "port de bras", "levé de genou", "angle droit", "ondulation", "immobilité", "contact", "de haut en bas", "grand-jeté"];
var _this = this;
this.annotations = this.source.getAnnotations().filter(function(annotation)
{
return _this.isGesture(annotation, null, _this.gestures);
});
};
/*
* Constructeur du Widget.
*/
IriSP.Widgets.Timeline.prototype = new IriSP.Widgets.Widget();
/*
* Indique si l'annotation passée en paramètre référence une gesture utilisée dans ce Front.
*/
IriSP.Widgets.Timeline.prototype.isGesture = function(element, index, array)
{
return ($.inArray(element.annotationType.contents.title, array) > -1);
}
/*
* Spécifie si on est en événements souris ou non.
* Est appelé dans le fichier :
* mosaic > fonction onMarkersReady.
*/
IriSP.Widgets.Timeline.prototype.setMouseInteractions = function(mouseInteractions)
{
this.mouseInteractions = mouseInteractions;
if(mouseInteractions)
{
this.markersDir += 'MI/';
}
}
/*
* Spécifie la langue pour l'affichage des marqueurs.
* Est appelé dans le fichier :
* mosaic > fonction onMarkersReady.
*/
IriSP.Widgets.Timeline.prototype.setLang = function(gesturesText)
{
this.gesturesText = gesturesText;
}
/*
* Fonction associée à l'événement : les marqueurs sont prêts.
* Est appelé dans le fichier :
* mosaic > fonction onPlayerLoad.
*/
IriSP.Widgets.Timeline.prototype.onMarkersReady = function() {}
/*
* Paramètres par défaut de la timeline.
*/
IriSP.Widgets.Timeline.prototype.defaults = {
minimized_height : 114,//44,
maximized_height : 114,
middle_height: 10,//4,
timelineBorderLength : 6,
minimize_timeout : 1500 // time before minimizing timeline after mouseout
};
/*
* Fonction appelée pour dessiner la timeline.
*/
IriSP.Widgets.Timeline.prototype.draw = function() {
this.$timeline = IriSP.jQuery('<div>')
.addClass("Ldt-Timeline")
.css(this.calculateTimelineCss(this.minimized_height));
this.$timelineMiddle = IriSP.jQuery('<div>')
.addClass("Ldt-TimelineMiddle")
.css(this.calculateTimelineMiddleCss(this.minimized_height, this.middle_height));
//On l'ajoute au widget.
this.$.append(this.$timeline);
this.$.append(this.$timelineMiddle);
var _this = this;
//On définit le slider.
this.$timeline.slider({
range: "min",
value: 0,
min: 0,
max: this.source.getDuration().milliseconds,
slide: function(event, ui) {
if(_this.player.popcorn)
{
_this.player.popcorn.currentTime(Math.floor(ui.value/1000));
_this.player.popcorn.trigger("IriSP.Mediafragment.setHashToTime");
}
//On supprime le marqueur précédemment affiché.
if(_this.previousMarkerIdx > -1)
{
var previousMarker = IriSP.jQuery("#" + _this.annotations[_this.previousMarkerIdx].id.replace(":", "_"));
_this.hideMarkerBig(previousMarker);
}
}
});
this.$handle = this.$timeline.find('.ui-slider-handle');
this.$handle.css(this.calculateHandleCss(this.minimized_height));
//On wrapp mouseover et mouse out.
this.$.mouseover(this.functionWrapper("onMouseover")).mouseout(this.functionWrapper("onMouseout"));
//On bind keypress.
IriSP.jQuery('body').keypress(function(evt) {_this.keyPress(evt)});
this.maximized = false;
this.timeoutId = false;
this.processMarkers();
};
/*
* Starts playing the video when it's ready.
*/
IriSP.Widgets.Timeline.prototype.ready = function() {
this.player.popcorn.play();
this.player.popcorn.mute();
// this.processMarkers();
}
/*
* Met à l'échelle une valeur de [A, B] vers [C, D].
* Est appelé dans les fichiers :
* pointers > fonction pointersTimelineSelection.
* search > fonction searchFilter.
* Timeline > fonctions processMarkers, onTimeupdate et timeDisplayUpdater.
*/
IriSP.Widgets.Timeline.prototype.scaleIntervals = function(A, B, C, D, val) {
if(A == B)
{
return (D - C) / 2;
}
else
{
return (D - C) * (val - A) / (B - A) + C;
}
}
/*
* On calcule les marqueurs.
* Est appelé dans le fichier :
* Timeline > fonction ready.
*/
IriSP.Widgets.Timeline.prototype.processMarkers = function() {
var _this = this;
var markers = "";
//On calcule la position en Y de la timeline.
var timelineMiddleTop = this.$timelineMiddle.position().top;
var TLHeight = this.$timeline.height()/2;
//Pour toutes les annotations, on crée les marqueurs.
for(var i = 0 ; i < this.annotations.length ; i++)
{
markers += "<div class='Ldt-Marker' id='" + this.annotations[i].id.replace(":", "_") + "'></div>";
}
//On les ajoute.
this.$.append(markers);
var markerHeight = IriSP.jQuery(".Ldt-Marker").height();
IriSP.jQuery(".Ldt-Marker").css("z-align", "150");
//Pour toutes les annotations.
for(var i = 0 ; i < this.annotations.length ; i++)
{
//On les place sur la timeline.
IriSP.jQuery("#" + this.annotations[i].id.replace(":", "_")).css(
{
top: timelineMiddleTop + "px",
left: Math.floor(+this.scaleIntervals(0, this.source.getDuration().getSeconds(), 0, this.$timeline.width(), this.annotations[i].begin/1000) + this.$timeline.position().left) + "px",
"margin-top": (-TLHeight - markerHeight/2) - this.top_epsilon + "px"
});
}
//On lance l'événement pour dire à popcorn que les marqueurs sont utilisables.
this.player.popcorn.trigger("markersready");
}
/*
* Fonction de recherche par gestures.
* Est appelé dans les fichiers :
* mosaic > fonctions onMouseUp, manageControlEvents et onMarkersReady.
* curvesDetector > fonction updateDists.
*/
IriSP.Widgets.Timeline.prototype.searchByGesture = function(typeName)
{
//Si le type existe.
if(typeName != '' || typeName != undefined)
{
if(_.include(this.gestures, typeName))
{
//On entre en mode recherche et on affiche les marqueurs sélectionnés.
this.currentMode = "SEARCH";
this.hideMarkersSearch(typeName);
this.isCurrentlyInASearchByGesture = true;
}
}
}
/*
* Fonction de suppression de recherche par gesures.
* Est appelé dans le fichier :
* pointers > checkIfPointerIsOnSearchNotification et removeSearchNotificationIfOnIt.
*/
IriSP.Widgets.Timeline.prototype.removeSearchByGesture = function()
{
this.hideMarkersSearch();
this.isCurrentlyInASearchByGesture = false;
}
/*
* Place le curseur sur la timeline en fonction de la touche pressée.
* Est appelé dans le fichier :
*/
IriSP.Widgets.Timeline.prototype.keyPress = function(e) {
var key = this.whichKey(e.which);
var time = 0;
//Entre 0 et 10, on met à jour la position du curseur dans la video.
if(key > -1 && key < 11)
{
time = this.source.getDuration().getSeconds()/10*key;
this.$timeline.slider("value",time);
this.player.popcorn.currentTime(time);
//On supprime le marqueur précédemment affiché.
if(this.previousMarkerIdx > -1)
{
var previousMarker = IriSP.jQuery("#" + this.annotations[this.previousMarkerIdx].id.replace(":", "_"));
this.hideMarkerBig(previousMarker);
}
}
//p ou P pour mettre en pause.
if(key == 21)
{
if(!this.paused)
{
this.paused = true;
this.player.popcorn.pause();
}
else
{
this.paused = false;
this.player.popcorn.play();
}
}
}
/*
* Donne une clé correspondante à une touche donnée.
* Est appelé dans le fichier :
* Timeline > fonction keyPress.
*/
IriSP.Widgets.Timeline.prototype.whichKey = function(code) {
var key;
if(code > 47 && code < 58)
{
return (code - 48);
}
if(code == 115 || code == 83)
{
return 11;
}
//p ou P pour mettre la vidéo en pause.
if(code == 112 || code == 80)
{
return 21;
}
switch(code)
{
case 224:
key = 0;
break;
case 38:
key = 1;
break;
case 233:
key = 2;
break;
case 34:
key = 3;
break;
case 39:
key = 4;
break;
case 40:
key = 5;
break;
case 45:
key = 6;
break;
case 232:
key = 7;
break;
case 95:
key = 8;
break;
case 231:
key = 9;
break;
default:
key = -1;
}
return key;
}
/*
* Fonction de sélection de la timeline.
* Est appelé dans le fichier :
* pointers > fonction pointersTimelineSelection.
*/
IriSP.Widgets.Timeline.prototype.selectTimeline = function() {
//On crée les bordures.
this.timelineSelected = true;
this.$timelineBorderUp = "<div class='TL_Borders' id='TL_BorderUp'></div>";
this.$timelineBorderDown = "<div class='TL_Borders' id='TL_BorderDown'></div>";
this.$timelineBorderLeft = "<div class='TL_Borders' id='TL_BorderLeft'></div>";
this.$timelineBorderRight = "<div class='TL_Borders' id='TL_BorderRight'></div>";
//Les flèches verticales aussi.
this.$arrowUp = "<div class='TL_Arrows' id='TL_ArrowUp'></div>";
this.$arrowDown = "<div class='TL_Arrows' id='TL_ArrowDown'></div>";
//On les ajoute.
this.$.append(this.$timelineBorderUp + this.$timelineBorderDown + this.$timelineBorderLeft + this.$timelineBorderRight + this.$arrowUp + this.$arrowDown);
//On calcule la position en Y de la timeline.
var timelineTop = IriSP.jQuery("#LdtPlayer").position().top + IriSP.jQuery("#LdtPlayer").height();
//On met les styles à jour.
IriSP.jQuery("#TL_BorderUp").css(
{
"margin-top": -this.$timeline.height() - this.top_epsilon,
left: this.$timeline.position().left,
width: this.$timeline.width(),
height: this.timelineBorderLength
});
IriSP.jQuery("#TL_BorderDown").css(
{
"margin-top": -this.timelineBorderLength - 2 - this.top_epsilon,
left: this.$timeline.position().left,
width: this.$timeline.width(),
height: this.timelineBorderLength
});
IriSP.jQuery("#TL_BorderLeft").css(
{
"margin-top": -this.$timeline.height() - this.top_epsilon,
left: this.$timeline.position().left,
width: this.timelineBorderLength,
height: this.$timeline.height()
});
IriSP.jQuery("#TL_BorderRight").css(
{
"margin-top": -this.$timeline.height() - this.top_epsilon,
left: +this.$timeline.position().left + this.$timeline.width() - this.timelineBorderLength - 2,
width: this.timelineBorderLength,
height: this.$timeline.height()
});
IriSP.jQuery("#TL_ArrowUp").css(
{
"background-image": "url(" + this.imgDir + "arrow_up.png)",
"margin-top": -this.$timeline.height() - IriSP.jQuery("#TL_ArrowUp").height() - this.top_epsilon,
left: this.$timeline.position().left - IriSP.jQuery("#TL_ArrowUp").width()/2,
});
IriSP.jQuery("#TL_ArrowDown").css(
{
"background-image": "url(" + this.imgDir + "arrow_down.png)",
"margin-top": -this.timelineBorderLength + this.timelineBorderLength - this.top_epsilon,
left: this.$timeline.position().left - IriSP.jQuery("#TL_ArrowUp").width()/2,
});
IriSP.jQuery(".Ldt-Timeline .ui-slider-range").css("background-image", "url(" + this.imgDir + "past_timeline.png)");
}
/*
* Déselectionne la timeline.
* Est appelé dans le fichier :
* playerControl > fonction exitTimeline.
*/
IriSP.Widgets.Timeline.prototype.deselectTimeline = function() {
//On supprime les éléments qui faisaient que la timeline était sélectionnée.
this.timelineSelected = false;
IriSP.jQuery(".TL_Borders").remove();
IriSP.jQuery(".TL_Arrows").remove();
IriSP.jQuery(".Ldt-Timeline .ui-slider-range").css("background-image", "url(" + this.imgDir + "selected_timeline.png)");
}
/*
* Se met à jour durant la lecture d'une video.
* Est appelé dans le fichier :
* Timeline
*/
IriSP.Widgets.Timeline.prototype.onTimeupdate = function() {
//On récupère la position du curseur en secondes.
var _time = this.player.popcorn.currentTime();
//Position des flèches au cas où la timeline serait sélectionnée.
var arrowLeft = Math.floor(+this.scaleIntervals(0, this.source.getDuration().getSeconds(), 0, this.$timeline.width(), _time) + this.$timeline.position().left) - IriSP.jQuery("#TL_ArrowUp").width()/2 + "px";
//On met à jour la position du slider en ms.
this.$timeline.slider("value",_time*1000);
//On affiche les flèches si la timeline est sélectionnée.
IriSP.jQuery(".TL_Arrows").css("display", "block");
IriSP.jQuery("#TL_ArrowUp").css("left", arrowLeft);
IriSP.jQuery("#TL_ArrowDown").css("left", arrowLeft);
//Si on a une distance de 500 ms à un marqueur, on l'affiche.
var nearestMarkerIdx = 0;
for(var i = 0 ; i < this.annotations.length ; i++)
{
//S'il existe des marqueurs dans l'intervalle de temps actuel (ici 500ms).
if(Math.abs(_time*1000 - this.annotations[i].begin.milliseconds) <= 250)
{
//On sélectionne le plus proche marqueur (dans les cas où il en existe plusieurs dans l'intervalle des 1s) ou bien le premier marqueur.
if(Math.abs(_time*1000 - this.annotations[i].begin.milliseconds) < Math.abs(_time*1000 - this.annotations[nearestMarkerIdx].begin.milliseconds) || i == nearestMarkerIdx)
{
//Si le prochain marqueur se situe après le curseur de lecture, on passe donc au marqueur le plus proche.
if(_time*1000 < this.annotations[i].begin.milliseconds)
{
nearestMarkerIdx = i;
//S'il y a un changement de marqueur (marqueur actuel différent du précédent).
if(nearestMarkerIdx != this.previousMarkerIdx)
{
var currentMarker = IriSP.jQuery("#" + this.annotations[nearestMarkerIdx].id.replace(":", "_"));
//S'il existe un marqueur précédent, on le cache.
if(this.previousMarkerIdx > -1)
{
var previousMarker = IriSP.jQuery("#" + this.annotations[this.previousMarkerIdx].id.replace(":", "_"));
this.hideMarkerBig(previousMarker);
}
this.showMarkerBig(currentMarker, this.annotations[nearestMarkerIdx].annotationType.contents.title);
//Mise à jour du marqueur précédent s'il y a un changement.
this.previousMarkerIdx = nearestMarkerIdx;
}
}
}
this.currentMarkerIdx = nearestMarkerIdx;
}
}
}
/*
* Met à jour l'affichage régulièrement.
* Est appelé dans le fichier :
* Timeline
*/
IriSP.Widgets.Timeline.prototype.timeDisplayUpdater = function() {
//On récupère la position du curseur en secondes.
var _time = this.player.popcorn.currentTime();
//Position des flèches au cas où la timeline serait sélectionnée.
var arrowLeft = Math.floor(+this.scaleIntervals(0, this.source.getDuration().getSeconds(), 0, this.$timeline.width(), _time) + this.$timeline.position().left) -
this.$timeline.slider("value",_time*1000);
//On affiche les flèches si la timeline est sélectionnée.
IriSP.jQuery(".TL_Arrows").css("display", "block");
IriSP.jQuery("#TL_ArrowUp").css("left", arrowLeft);
IriSP.jQuery("#TL_ArrowDown").css("left", arrowLeft);
}
/*
* Fonction appelée quand la souris est au dessus de la timeline.
*/
IriSP.Widgets.Timeline.prototype.onMouseover = function() {}
/*
* Fonction appelée quand la souris est hors de la timeline.
*/
IriSP.Widgets.Timeline.prototype.onMouseout = function() {}
/*
* Fonction appelée pour modifier la hauteur de la timeline.
*/
IriSP.Widgets.Timeline.prototype.animateToHeight = function(_height) {}
/*
* Calcule le css de la timeline.
* Est appelé dans le fichier :
* Timeline > fonction draw.
*/
IriSP.Widgets.Timeline.prototype.calculateTimelineCss = function(_size) {
//Longueur du player.
var middleWidth = this.player.config.gui.width;
var TLHeight = _size;
//On met à jour la marge, les coordonnées et positions de la timeline.
return {
position: "absolute",
top: "0px",
left: "0px",
width: middleWidth + "px",
height: TLHeight + "px",
"margin-top": (-this.minimized_height - this.top_epsilon) + "px",
"z-align": "50"
};
}
/*
* Calcule le css de la barre grise de milieu de la timeline.
* Est appelé dans le fichier :
* Timeline > fonction draw.
*/
IriSP.Widgets.Timeline.prototype.calculateTimelineMiddleCss = function(_size, _middleSize) {
//Longueur du player.
var middleWidth = this.player.config.gui.width;
//On met à jour la marge, les coordonnées et positions de la barre grise de milieu de la timeline.
return {
position: "absolute",
top: "0px",
left: "0px",
width: middleWidth + "px",
height: _middleSize + "px",
"margin-top": (-this.minimized_height/2 - _middleSize/2 - this.top_epsilon) + "px",
"z-align": "100"
};
}
/*
* Calcule le css de la portion de la timeline qui a déjà été lue.
* Est appelé dans le fichier :
* Timeline > fonction draw.
*/
IriSP.Widgets.Timeline.prototype.calculateHandleCss = function(_size) {
return {
position: "absolute",
top: "0px",
left: "0px",
height: (2 + _size) + "px",
width: (2 + _size) + "px",
"margin-left": -Math.ceil(2 + _size / 2) + "px",
"z-align": "60"
}
}
/*
* Affiche les marqueurs lorsqu'ils sont affichés au passage du curseur.
* Est appelé dans le fichier :
* Timeline > fonction onTimeupdate.
*/
IriSP.Widgets.Timeline.prototype.showMarkerBig = function(marker, type) {
//Si le marqueur est déjà affiché, on part.
if(this.markerBigShown)
{
return;
}
//On annule le masquage du pointeur.
clearTimeout(this.hideTimeout);
var _this = this;
//On met à jour la position du marqueur.
var markerTop, markerLeft;
if(marker.position() == null)
{
markerTop = 0;
markerLeft = 0;
}
else
{
markerTop = marker.position().top;
markerLeft = marker.position().left;
}
//Ses dimensions aussi.
var markerWidth = marker.width(), markerHeight = marker.height();
//On spécifie qu'il est affiché.
this.markerBigShown = true;
//On le crée.
var markerBig = "<div class='TL_MarkersBig' id='MB_Text'>" + this.gesturesText[IriSP.jQuery.inArray(type, this.gestures)] + "<div class='TL_MarkersBig' id='MB_Spike'></div></div><div class='TL_MarkersBig' id='MB_Pic'></div>";
//On l'ajoute.
this.$.append(markerBig);
//On forme ses éléments.
var markerBigText = IriSP.jQuery("#MB_Text");
var markerBigSpike = IriSP.jQuery("#MB_Spike");
var markerBigPic = IriSP.jQuery("#MB_Pic");
//On spécifie leurs coordonnées et dimensions.
var markerBigTextWidth = markerBigText.outerWidth(), markerBigTextHeight = markerBigText.outerHeight();
var markerBigSpikeWidth = markerBigSpike.width(), markerBigSpikeHeight = markerBigSpike.height();
var markerBigPicWidth = markerBigPic.width(), markerBigPicHeight = markerBigPic.height();
var markerBigPicTop = +parseInt(marker.css("margin-top")) + markerHeight, markerBigPicLeft = (markerLeft - markerBigPicWidth/2 + markerWidth/2);
var markerBigTextTop = (parseInt(marker.css("margin-top")) - markerBigTextHeight - markerBigSpikeHeight), markerBigTextLeft = (markerLeft - (markerBigTextWidth - markerBigSpikeWidth)/2);
var markerBigSpikeLeft = ((markerBigTextWidth - markerBigSpikeWidth)/2);
//On va chercher les images correspondantes.
marker.css("background-image", "url(" + this.imgDir + "selected_marker.png)");
//On met à jour leur apparence.
IriSP.jQuery("#MB_Text").css(
{
top: markerBigTextTop,
left: markerBigTextLeft
});
IriSP.jQuery("#MB_Spike").css(
{
left: markerBigSpikeLeft
});
IriSP.jQuery("#MB_Pic").css(
{
"background-image": "url(" + this.markersDir + type + ".png)",
top: markerBigPicTop,
left: markerBigPicLeft,
"z-index": "400"
});
//On l'affiche.
IriSP.jQuery(".TL_MarkersBig").fadeTo(this.markerShowTime, "1");
//On rajoute un timeout pour supprimer le marqueur après un certain temps.
this.hideTimeout = setTimeout(function()
{
_this.hideMarkerBig(marker);
}, this.markerLastTime);
}
/*
* Cache un marqueur.
* Est appelé dans le fichier :
* Timeline > fonctions draw, keyPress, onTimeupdate et showMarkerBig.
*/
IriSP.Widgets.Timeline.prototype.hideMarkerBig = function(marker) {
//S'il n'est pas affiché, on part.
if(!this.markerBigShown)
{
return;
}
//On lui remet son apparence initiale.
this.currentMarker = -1;
this.markerBigShown = false;
marker.css("background-image", "url(" + this.imgDir + "marker.png)");
//On efface ce qui était affiché du marqueur.
IriSP.jQuery(".TL_MarkersBig").fadeOut(this.markerShowTime).remove();
}
/*
* Affiche le bas des marqueurs correspondants à la recherche.
* Est appelé dans le fichier :
* Timeline > fonction hideMarkersSearch.
*/
IriSP.Widgets.Timeline.prototype.showMarkersSearchByType = function(type) {
//Si on est en mode SEARCH.
if(this.currentMode != "SEARCH")
{
return;
}
var _this = this;
//On récupère les annotations.
var markersSearch = "", markersPicSearch = "";
//Pour chaque annotation, on ajoute un double.
for(var i = 0 ; i < this.annotations.length ; i++)
{
//Si elle correspond à la recherche.
if(this.annotations[i].annotationType.contents.title == type)
{
//On récupère le marqueur associé à l'annotation.
var markerId = this.annotations[i].id.replace(":", "_");
markersSearch += "<div class='search_Marker' id='search_Marker_" + markerId + "'></div>";
markersPicSearch += "<div class='search_MBPic' id='search_Pic_" + markerId + "'></div>";
}
}
this.$.append(markersSearch + markersPicSearch);
//On place chaque double.
for(var i = 0 ; i < this.annotations.length ; i++)
{
//Si elle correspond à la recherche.
if(this.annotations[i].annotationType.contents.title == type)
{
//On calcule les coordonnées et dimensions du marqueur.
var markerId = this.annotations[i].id.replace(":", "_"), marker = IriSP.jQuery("#" + markerId);
var markerTop = marker.position().top, markerLeft = marker.position().left, markerWidth = marker.width(), markerHeight = marker.height();
var markerBigPicWidth = parseInt(IriSP.jQuery(".search_MBPic").css("width")), markerBigPicHeight = parseInt(IriSP.jQuery(".search_MBPic").css("height")), markerBigPicTop = +parseInt(marker.css("margin-top")) + markerHeight, markerBigPicLeft = (markerLeft - markerBigPicWidth/2 + markerWidth/2);
//On calcule son apparence et on le fait apparaître.
IriSP.jQuery("#search_Pic_" + markerId).css(
{
position: "absolute",
"background-image": "url(" + this.markersDir + type + ".png)",
top: markerBigPicTop,
left: markerBigPicLeft,
"z-index": "300"
}).fadeTo(this.markerShowTime, "1");
IriSP.jQuery("#search_Marker_" + markerId).css(
{
position: "absolute",
top: _this.$timelineMiddle.position().top - _this.top_epsilon,
"margin-top": (-_this.$timeline.height()/2 - markerHeight/2),
"background-image": "url(" + this.imgDir + "selected_marker.png)",
left: markerLeft,
"z-index": "300"
}).fadeTo(this.markerShowTime, "1");
}
}
}
/*
* Enlever une recherche faite précédemment.
* Est appelé dans le fichier :
* Timeline > fonctions searchByGesture et removeSearchByGesture.
*/
IriSP.Widgets.Timeline.prototype.hideMarkersSearch = function(type) {
//Si on est en mode SEARCH.
if(this.currentMode != "SEARCH")
{
return;
}
var _this = this;
//On efface tous les marqueurs affichés.
IriSP.jQuery(".search_MBPic").fadeOut(this.markerShowTime, function()
{
IriSP.jQuery("div").remove(".search_MBPic");
});
IriSP.jQuery(".search_Marker").fadeOut(this.markerShowTime, function()
{
IriSP.jQuery("div").remove(".search_Marker");
//Si le type est définit, c'est qu'on souhaite remplacer cette recherche par une autre.
if(type == undefined)
{
_this.currentMode = "VIDEO";
}
else
{
_this.showMarkersSearchByType(type);
return;
}
});
//Si à la base il n'y avait pas de marqueurs affichés, on crée une nouvelle recherche si le type est définit.
if(IriSP.jQuery(".search_Marker").length == 0 && type != undefined)
{
this.showMarkersSearchByType(type);
}
}
/*
* Libère le player.
* Est appelé dans les fichiers :
* neighbours > fonction moveToNeighbour.
* zoomInteractions > fonction unzoom.
*/
IriSP.Widgets.Timeline.prototype.freePlayer = function()
{
IriSP.jQuery('body').unbind('keypress');
IriSP.jQuery('.notifications').remove();
}
/*
* Va au marqueur suivant/précédant lors d'un swipe right/left dans une lecture simple.
* Prend comme argument le fait qu'il s'agisse d'un swipe left ou non (en prenant en condition toujours vraie
* que la fonction est appelée si et seulement si il y a swipe et que l'utilisateur ne tente pas d'aller vers un voisin.
* Est appelé dans le fichier :
* mosaic > fonction manageControlEvents.
*/
IriSP.Widgets.Timeline.prototype.switchToMarker = function(isSwipeLeft, searchedGesture)
{
//On prend le temps actuel du curseur en ms.
var currentCursorPosition = this.player.popcorn.currentTime() * 1000;
//Position visée.
var targetCursorPosition = currentCursorPosition;
//Distance minimum de l'annotation par rapport au curseur et son index, ainsi que l'index - 1 pour le cas du swipe right.
var minDistance = this.source.getDuration().milliseconds, minIdx = 0, mindIdx_1 = 0;
//Condition de sélection du marqueur selon le type de swipe.
var swipeCondition;
//Si il y a au moins 1 annotation.
if(this.annotations && this.annotations.length > 0)
{
//Pour toutes les annotations, on prend celle qui est la plus proche et supérieure à la position.
for(var i = 0 ; i < this.annotations.length ; i++)
{
swipeCondition = (isSwipeLeft ? (currentCursorPosition < this.annotations[i].begin && minDistance > Math.abs(currentCursorPosition - this.annotations[i].begin)) : (currentCursorPosition > this.annotations[i].begin && minDistance > Math.abs(currentCursorPosition - this.annotations[i].begin)));
if(swipeCondition)
{
//Si on recherche une gesture.
if(searchedGesture != '')
{
//Si l'annotation actuelle ne correspond pas à la gesture recherchée, on passe.
if(this.annotations[i].annotationType.contents.title != searchedGesture)
{
continue;
}
}
//On calcule la plus petite distance entre le marqueur marqueur actuel et les autres.
minDistance = (currentCursorPosition - this.annotations[i].begin);
minIdx = i;
}
}
//On obtient la position du plus proche marqueur.
targetCursorPosition = this.annotations[minIdx].begin;
//Si le marqueur est situé minimum à 1s du début de la video, on place la position cible à 1s avant celle du marqueur recherché.
if(this.annotations[minIdx].begin > 1000)
{
targetCursorPosition -= 1000;
}
}
//On place le marqueur au niveau de la position cible.
this.player.popcorn.currentTime(targetCursorPosition / 1000);
}
/*
* Indique s'il y a des marqueurs devant le curseur (pour une recherche).
* Est appelé dans le fichier :
* mosaic > fonction manageControlEvents.
*/
IriSP.Widgets.Timeline.prototype.isAMarkerAhead = function(searchedGesture)
{
if(searchedGesture == '')
{
return true;
}
//On prend le temps actuel du curseur en ms.
var currentCursorPosition = this.player.popcorn.currentTime() * 1000;
//Position visée.
var targetCursorPosition = currentCursorPosition;
//Distance minimum de l'annotation par rapport au curseur et son index, ainsi que l'index - 1 pour le cas du swipe right.
var minDistance = this.source.getDuration().milliseconds, minIdx = 0, mindIdx_1 = 0;
//Si il y a au moins 1 annotation.
if(this.annotations && this.annotations.length > 0)
{
//Pour toutes les annotations, on prend celle qui est la plus proche et supérieure à la position.
for(var i = 0 ; i < this.annotations.length ; i++)
{
if(this.annotations[i].annotationType.contents.title == searchedGesture && currentCursorPosition < this.annotations[i].begin)
{
return true;
}
}
}
//Si elle n'a pas été trouvée on renvoie faux.
return false;
}
/*
* Quand on entre dans la vidéo après un filtrage, on va au premier marqueur correspondant à la recherche (à l'exception d'une recherche infructueuse).
* Est appelé dans les fichiers :
* mosaic > fonctions onMouseUp et onMarkersReady.
* curvesDetector > fonction updateDists.
*/
IriSP.Widgets.Timeline.prototype.goToFirstSearchedMarker = function(gesture)
{
if(_.include(this.gestures, gesture))
{
if(this.annotations && this.annotations.length > 0)
{
var minIdx = 0, minPosition = this.source.getDuration().milliseconds, targetCursorPosition = 0;
//On parcourt les annotations, pour chaque correspondant à la gesture recherchée, on trouve celle qui se trouve à la position minimum.
for(var i = 0 ; i < this.annotations.length ; i++)
{
//Si le marker n'est pas du type recherché, on passe.
if(this.annotations[i].annotationType.contents.title != gesture)
{
continue;
}
else if(minPosition > this.annotations[i].begin)
{
minPosition = this.annotations[i].begin;
minIdx = i;
}
}
targetCursorPosition = this.annotations[minIdx].begin;
//Si le marqueur est situé minimum à 1s du début de la video, on place la position cible à 1s avant celle du marqueur recherché.
if(this.annotations[minIdx].begin > 1000)
{
targetCursorPosition -= 1000;
}
//On place le marqueur au niveau de la position cible.
this.player.popcorn.currentTime(targetCursorPosition / 1000);
}
}
}
/*
* Renvoie vrai si il y a au moins une gesture de notre recherche dans les marqueurs de la video.
* Est appelé dans les fichiers :
* mosaic > fonctions onMouseUp et onMarkersReady.
* curvesDetector > fonction updateDists.
*/
IriSP.Widgets.Timeline.prototype.atLeastOneSearchMarker = function(gesture)
{
if(_.include(this.gestures, gesture))
{
if(this.annotations && this.annotations.length > 0)
{
//On parcourt les annotations, pour chaque correspondant à la gesture recherchée, on trouve celle qui se trouve à la position minimum.
for(var i = 0 ; i < this.annotations.length ; i++)
{
//Si le marker est reconnu, c'est bon.
if(this.annotations[i].annotationType.contents.title == gesture)
{
return true;
}
}
return false;
}
}
}