FRONT IDILL :
Player implemented in the mosaic.
/*
The Timeline Widget fits right under the video
*/
IriSP.Widgets.Timeline = function(player, config) {
IriSP.Widgets.Widget.call(this, player, config);
this.bindPopcorn("timeupdate","onTimeupdate");
this.bindPopcorn("loadedmetadata","ready");
//this.bindPopcorn("IriSP.PlayerWidget.MouseOver","onMouseover");
//this.bindPopcorn("IriSP.PlayerWidget.MouseOut","onMouseout");
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 = "player/markers/";
};
IriSP.Widgets.Timeline.prototype = new IriSP.Widgets.Widget();
IriSP.Widgets.Timeline.prototype.defaults = {
minimized_height : 44,
maximized_height : 44,
middle_height: 4,
timelineBorderLength : 6,
minimize_timeout : 1500 // time before minimizing timeline after mouseout
};
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));
/*this.$timelineContainer = IriSP.jQuery('<div>')
.addClass("Ldt-TimelineContainer");
this.$timelineContainer.append(this.$timeline);
this.$timelineContainer.append(this.$timelineMiddle);*/
this.$.append(this.$timeline);
this.$.append(this.$timelineMiddle);
var _this = this;
this.$timeline.slider({
range: "min",
value: 0,
min: 0,
max: this.source.getDuration().milliseconds,
slide: function(event, ui) {
_this.player.popcorn.currentTime(Math.floor(ui.value/1000));
_this.player.popcorn.trigger("IriSP.Mediafragment.setHashToTime");
// console.log("manual " + _this.previousMarkerIdx);
//On supprime le marqueur précédemment affiché si c'est le cas.
if(_this.previousMarkerIdx > -1)
{
var annotations = _this.source.getAnnotations();
// console.log("EXT hide idx " + _this.previousMarkerIdx);
var previousMarker = IriSP.jQuery("#" + annotations[_this.previousMarkerIdx].id.replace(":", "_"));
_this.hideMarkerBig(previousMarker);
// console.log("EXT hide " + _this.previousMarkerIdx);
}
}
});
this.$handle = this.$timeline.find('.ui-slider-handle');
this.$handle.css(this.calculateHandleCss(this.minimized_height));
this.$
.mouseover(this.functionWrapper("onMouseover"))
.mouseout(this.functionWrapper("onMouseout"));
IriSP.jQuery('body').keypress(function(evt) {_this.keyPress(evt)});
this.maximized = false;
this.timeoutId = false;
};
/*
* Starts playing the video when it's ready.
*/
IriSP.Widgets.Timeline.prototype.ready = function() {
this.player.popcorn.play();
this.processMarkers();
}
/*
* Scale a value from [A, B] to [C, D].
*/
IriSP.Widgets.Timeline.prototype.scaleIntervals = function(A, B, C, D, val) {
if(C == D)
{
return C;
}
if(B != A)
{
return D / (B - A) * (val - A);
}
else
{
//If A and B have the same sign.
if(A * B > 0)
{
//If they are positive.
if(A > 0)
{
return (D - C)/2;
}
else
{
return (C - D)/2;
}
}
else
{
return (C + D)/2;
}
}
}
/*
* Process the markers.
*/
IriSP.Widgets.Timeline.prototype.processMarkers = function() {
var _this = this;
var annotations = this.source.getAnnotations();
var markers = "";
var timelineMiddleTop = this.$timelineMiddle.position().top;
for(var i = 0 ; i < annotations.length ; i++)
{
markers += "<div class='Ldt-Marker' id='" + annotations[i].id.replace(":", "_") + "'></div>";
// console.log(annotations[i].begin.milliseconds);
}
this.$.append(markers);
var markerHeight = IriSP.jQuery(".Ldt-Marker").height();
IriSP.jQuery(".Ldt-Marker").css("z-align", "150");
for(var i = 0 ; i < annotations.length ; i++)
{
IriSP.jQuery("#" + annotations[i].id.replace(":", "_")).css(
{
top: timelineMiddleTop + "px",
left: Math.floor(+this.scaleIntervals(0, this.source.getDuration().getSeconds(), 0, this.$timeline.width(), annotations[i].begin/1000) + this.$timeline.position().left) + "px",
"margin-top": (-_this.$timeline.height()/2 - markerHeight/2) - this.top_epsilon + "px"
});
}
}
/*
* Place the cursor on the timeline depending on the keytyped.
*/
IriSP.Widgets.Timeline.prototype.keyPress = function(e) {
var key = this.whichKey(e.which);
var time = 0;
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é si c'est le cas.
if(this.previousMarkerIdx > -1)
{
var annotations = this.source.getAnnotations();
// console.log("EXT hide idx " + this.previousMarkerIdx);
var previousMarker = IriSP.jQuery("#" + annotations[this.previousMarkerIdx].id.replace(":", "_"));
this.hideMarkerBig(previousMarker);
// console.log("EXT hide " + this.previousMarkerIdx);
}
}
if(key == 11)
{
if(!this.timelineSelected)
{
this.currentMode = "TIMELINE";
this.selectTimeline();
}
else
{
this.currentMode = "VIDEO";
this.deselectTimeline();
}
}
if(key == 12)
{
this.hideMarkersSearch();
}
if(key == 13)
{
this.currentMode = "SEARCH";
this.hideMarkersSearch("screw");
/*this.currentMode = "SEARCH";
this.showMarkersSearchByType("screw");*/
}
if(key == 14)
{
this.currentMode = "SEARCH";
this.hideMarkersSearch("contact");
/*this.currentMode = "SEARCH";
this.showMarkersSearchByType("contact");*/
}
if(key == 21)
{
// console.log(this);
if(!this.paused)
{
this.paused = true;
this.player.popcorn.pause();
}
else
{
this.paused = false;
this.player.popcorn.play();
}
}
}
/*
* Find the key corresponding to a given code.
*/
IriSP.Widgets.Timeline.prototype.whichKey = function(code) {
var key;
console.log(code);
if(code > 47 && code < 58)
{
return (code - 48);
}
if(code == 115 || code == 83)
{
return 11;
}
//q ou Q pour quitter une recherche.
if(code == 113 || code == 81)
{
return 12;
}
//p ou P pour mettre la vidéo en pause.
if(code == 112 || code == 80)
{
return 21;
}
//a ou A pour une recherche de type screw.
if(code == 97 || code == 65)
{
return 13;
}
//z ou Z pour une recherche de type contact.
if(code == 122 || code == 90)
{
return 14;
}
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;
}
IriSP.Widgets.Timeline.prototype.selectTimeline = function() {
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>";
this.$arrowUp = "<div class='TL_Arrows' id='TL_ArrowUp'></div>";
this.$arrowDown = "<div class='TL_Arrows' id='TL_ArrowDown'></div>";
this.$.append(this.$timelineBorderUp + this.$timelineBorderDown + this.$timelineBorderLeft + this.$timelineBorderRight + this.$arrowUp + this.$arrowDown);
var timelineTop = IriSP.jQuery("#LdtPlayer").position().top + IriSP.jQuery("#LdtPlayer").height();
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)");
}
IriSP.Widgets.Timeline.prototype.deselectTimeline = function() {
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)");
}
IriSP.Widgets.Timeline.prototype.onTimeupdate = function() {
var _time = this.player.popcorn.currentTime();
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";
var annotations = this.source.getAnnotations();
this.$timeline.slider("value",_time*1000);
IriSP.jQuery(".TL_Arrows").css("display", "block");
IriSP.jQuery("#TL_ArrowUp").css("left", arrowLeft);
IriSP.jQuery("#TL_ArrowDown").css("left", arrowLeft);
// this.player.popcorn.trigger("IriSP.Arrow.updatePosition",{widget: this.type, time: 1000 * _time});
//Si on a une distance de 500 ms à un marqueur, on l'affiche.
var nearestMarkerIdx = 0;
for(var i = 0 ; i < annotations.length ; i++)
{
//S'il existe des marqueurs dans l'intervalle de temps actuel (ici 500ms).
if(Math.abs(_time*1000 - annotations[i].begin.milliseconds) <= 250)
{
// console.log("1) i = " + i + " " + Math.abs(_time*1000 - annotations[i].begin.milliseconds));
//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 - annotations[i].begin.milliseconds) < Math.abs(_time*1000 - annotations[nearestMarkerIdx].begin.milliseconds) || i == nearestMarkerIdx)
{
// console.log("2) " + Math.abs(_time*1000 - annotations[i].begin.milliseconds) + " < " + Math.abs(_time*1000 - annotations[nearestMarkerIdx].begin.milliseconds));
//Si le prochain marqueur se situe après le curseur de lecture, on passe donc au marqueur le plus proche.
if(_time*1000 < annotations[i].begin.milliseconds)
{
// console.log("3) " + _time*1000 + " < " + annotations[i].begin.milliseconds);
// console.log("4) " + "nearest = " + i);
nearestMarkerIdx = i;
// console.log("5a0) before");
//S'il y a un changement de marqueur (marqueur actuel différent du précédent).
if(nearestMarkerIdx != this.previousMarkerIdx)
{
var currentMarker = IriSP.jQuery("#" + annotations[nearestMarkerIdx].id.replace(":", "_"));
//S'il existe un marqueur précédent, on le cache.
if(this.previousMarkerIdx > -1)
{
// console.log("hide idx " + this.previousMarkerIdx);
var previousMarker = IriSP.jQuery("#" + annotations[this.previousMarkerIdx].id.replace(":", "_"));
this.hideMarkerBig(previousMarker);
// console.log("5a) hide " + this.previousMarkerIdx);
}
// console.log("5b) show " + nearestMarkerIdx);
this.showMarkerBig(currentMarker, annotations[nearestMarkerIdx].annotationType.contents.title);
//Mise à jour du marqueur précédent s'il y a un changement.
this.previousMarkerIdx = nearestMarkerIdx;
// console.log("MAJ : " + this.previousMarkerIdx);
}
}
}
// nearestMarker = (Math.abs(_time*1000 - annotations[i].begin.milliseconds) < Math.abs(_time*1000 - annotations[nearestMarker].begin.milliseconds) && annotations[i].begin.milliseconds >= annotations[nearestMarker].begin.milliseconds && annotations[i].begin.milliseconds >= _time*1000) ? i : nearestMarker;
this.currentMarkerIdx = nearestMarkerIdx;
// this.showMarkerBig(IriSP.jQuery("#" + annotations[i].id.replace(":", "_")), annotations[i].annotationType.contents.title);
}
}
}
IriSP.Widgets.Timeline.prototype.timeDisplayUpdater = function() {
var _time = this.player.popcorn.currentTime();
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);
IriSP.jQuery(".TL_Arrows").css("display", "block");
IriSP.jQuery("#TL_ArrowUp").css("left", arrowLeft);
IriSP.jQuery("#TL_ArrowDown").css("left", arrowLeft);
// this.player.popcorn.trigger("IriSP.Arrow.updatePosition",{widget: this.type, time: 1000 * _time});
}
IriSP.Widgets.Timeline.prototype.onMouseover = function() {
/*if (this.timeoutId) {
window.clearTimeout(this.timeoutId);
this.timeoutId = false;
}
if (!this.maximized) {
this.animateToHeight(this.maximized_height);
this.maximized = true;
}*/
}
IriSP.Widgets.Timeline.prototype.onMouseout = function() {
/*if (this.timeoutId) {
window.clearTimeout(this.timeoutId);
this.timeoutId = false;
}
var _this = this;
this.timeoutId = window.setTimeout(function() {
if (_this.maximized) {
_this.animateToHeight(_this.minimized_height);
_this.maximized = false;
}
_this.timeoutId = false;
}, this.minimize_timeout);*/
}
IriSP.Widgets.Timeline.prototype.animateToHeight = function(_height) {
/*this.$timeline.stop().animate(
this.calculateTimelineCss(_height),
500,
function() {
IriSP.jQuery(this).css("overflow","visible");
});
this.$handle.stop().animate(
this.calculateHandleCss(_height),
500,
function() {
IriSP.jQuery(this).css("overflow","visible");
});*/
}
IriSP.Widgets.Timeline.prototype.calculateTimelineCss = function(_size) {
var middleWidth = this.player.config.gui.width;
return {
position: "absolute",
top: "0px",
left: "0px",
width: middleWidth + "px",
height: _size + "px",
"margin-top": (-this.minimized_height - this.top_epsilon) + "px",
"z-align": "50"
};
}
IriSP.Widgets.Timeline.prototype.calculateTimelineMiddleCss = function(_size, _middleSize) {
var middleWidth = this.player.config.gui.width;
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"
};
}
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"
}
}
IriSP.Widgets.Timeline.prototype.showMarkerBig = function(marker, type) {
// console.log("avant");
if(this.markerBigShown)
{
return;
}
// console.log("apres");
clearTimeout(this.hideTimeout);
var _this = this;
var markerTop = marker.position().top, markerLeft = marker.position().left, markerWidth = marker.width(), markerHeight = marker.height();
this.markerBigShown = true;
var markerBig = "<div class='TL_MarkersBig' id='MB_Text'>" + type + "<div class='TL_MarkersBig' id='MB_Spike'></div></div><div class='TL_MarkersBig' id='MB_Pic'></div>";
this.$.append(markerBig);
var markerBigText = IriSP.jQuery("#MB_Text");
var markerBigSpike = IriSP.jQuery("#MB_Spike");
var markerBigPic = IriSP.jQuery("#MB_Pic");
var markerBigTextWidth = markerBigText.outerWidth(), markerBigTextHeight = markerBigText.outerHeight();
var markerBigSpikeWidth = markerBigSpike.width(), markerBigSpikeHeight = markerBigSpike.height();
var markerBigPicWidth = markerBigPic.width(), markerBigPicHeight = markerBigPic.height();
var markerBigPicTop = +parseFloat(marker.css("margin-top")) + markerHeight, markerBigPicLeft = (markerLeft - markerBigPicWidth/2 + markerWidth/2);
var markerBigTextTop = (parseFloat(marker.css("margin-top")) - markerBigTextHeight - markerBigSpikeHeight), markerBigTextLeft = (markerLeft - (markerBigTextWidth - markerBigSpikeWidth)/2);
var markerBigSpikeLeft = ((markerBigTextWidth - markerBigSpikeWidth)/2);
marker.css("background-image", "url(" + this.imgDir + "selected_marker.png)");
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
});
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);
}
IriSP.Widgets.Timeline.prototype.hideMarkerBig = function(marker) {
if(!this.markerBigShown)
{
return;
}
this.currentMarker = -1;
this.markerBigShown = false;
marker.css("background-image", "url(" + this.imgDir + "marker.png)");
IriSP.jQuery(".TL_MarkersBig").fadeOut(this.markerShowTime).remove();
}
/*
* Affiche le bas des marqueurs correspondants à la recherche.
*/
IriSP.Widgets.Timeline.prototype.showMarkersSearchByType = function(type) {
//Si on est en mode SEARCH.
if(this.currentMode != "SEARCH")
{
return;
}
console.log('in');
var _this = this;
//On récupère les annotations.
var annotations = this.source.getAnnotations();
var markersSearch = "", markersPicSearch = "";
//Pour chaque annotation, on ajoute un double.
for(var i = 0 ; i < annotations.length ; i++)
{
//Si elle correspond à la recherche.
if(annotations[i].annotationType.contents.title == type)
{
//On récupère le marqueur associé à l'annotation.
var markerId = 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 < annotations.length ; i++)
{
//Si elle correspond à la recherche.
if(annotations[i].annotationType.contents.title == type)
{
var markerId = 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 = parseFloat(IriSP.jQuery(".search_MBPic").css("width")), markerBigPicHeight = parseFloat(IriSP.jQuery(".search_MBPic").css("height")), markerBigPicTop = +parseFloat(marker.css("margin-top")) + markerHeight, markerBigPicLeft = (markerLeft - markerBigPicWidth/2 + markerWidth/2);
// console.log(markerLeft + " - " + IriSP.jQuery(".search_MBPic").css("width") + " " + markerBigPicWidth + "/2 " + markerWidth + "/2");
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)",
//top: markerTop,
left: markerLeft,
"z-index": "300"
}).fadeTo(this.markerShowTime, "1");
}
}
}
/*
* Enlever une recherche faite précédemment.
*/
IriSP.Widgets.Timeline.prototype.hideMarkersSearch = function(type) {
//Si on est en mode SEARCH.
if(this.currentMode != "SEARCH")
{
return;
}
var _this = this;
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");
if(type == undefined)
{
_this.currentMode = "VIDEO";
}
else
{
// console.log(_this.currentMode);
_this.showMarkersSearchByType(type);
return;
}
});
if(IriSP.jQuery(".search_Marker").length == 0 && type != undefined)
{
// console.log(this.currentMode);
this.showMarkersSearchByType(type);
}
}