diff -r 45c889eae324 -r 2c7fc855eba8 front_idill/src/player/metadataplayer/Timeline.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/front_idill/src/player/metadataplayer/Timeline.js Fri May 11 11:04:06 2012 +0200 @@ -0,0 +1,704 @@ +/* + 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('
') + .addClass("Ldt-Timeline") + .css(this.calculateTimelineCss(this.minimized_height)); + this.$timelineMiddle = IriSP.jQuery('
') + .addClass("Ldt-TimelineMiddle") + .css(this.calculateTimelineMiddleCss(this.minimized_height, this.middle_height)); + + /*this.$timelineContainer = IriSP.jQuery('
') + .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 += "
"; + // 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 = "
"; + this.$timelineBorderDown = "
"; + this.$timelineBorderLeft = "
"; + this.$timelineBorderRight = "
"; + + this.$arrowUp = "
"; + this.$arrowDown = "
"; + + 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 = "
" + type + "
"; + 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 += "
"; + markersPicSearch += "
"; + } + } + + 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); + } +} \ No newline at end of file