src/js/widgets/polemicWidget.js
changeset 843 75ba66457232
parent 842 4ae2247a59f4
child 874 38b65761a7d5
equal deleted inserted replaced
53:7b55777486c3 843:75ba66457232
       
     1 /* 
       
     2  *   
       
     3  *  Copyright 2010 Institut de recherche et d'innovation 
       
     4  *  contributor(s) : Samuel Huron 
       
     5  *   
       
     6  *  contact@iri.centrepompidou.fr
       
     7  *  http://www.iri.centrepompidou.fr 
       
     8  *   
       
     9  *  This software is a computer program whose purpose is to show and add annotations on a video .
       
    10  *  This software is governed by the CeCILL-C license under French law and
       
    11  *  abiding by the rules of distribution of free software. You can  use, 
       
    12  *  modify and/ or redistribute the software under the terms of the CeCILL-C
       
    13  *  license as circulated by CEA, CNRS and INRIA at the following URL
       
    14  *  "http://www.cecill.info". 
       
    15  *  
       
    16  *  The fact that you are presently reading this means that you have had
       
    17  *  knowledge of the CeCILL-C license and that you accept its terms.
       
    18 */
       
    19 // CHART TIMELINE / VERSION PROTOTYPE  ::
       
    20 
       
    21 /** the polemic widget */
       
    22 IriSP.PolemicWidget = function(Popcorn, config, Serializer) {
       
    23   IriSP.Widget.call(this, Popcorn, config, Serializer);
       
    24  
       
    25   this.userPol    = new Array();
       
    26   this.userNoPol  = new Array();
       
    27   this.userst      = new Array();
       
    28   this.numberOfTweet = 0;
       
    29   this.Users;
       
    30   this.TweetPolemic;
       
    31   this.yMax        = this.height; 
       
    32   this.PaperSlider;
       
    33   this.heightOfChart;
       
    34   this.tweets  = new Array();
       
    35   this.svgElements = {};
       
    36   
       
    37   this.oldSearchMatches = [];
       
    38 };
       
    39 
       
    40 IriSP.PolemicWidget.prototype = new IriSP.Widget();
       
    41   
       
    42 IriSP.PolemicWidget.prototype.draw = function() {
       
    43   
       
    44     // variable 
       
    45     // yMax
       
    46     
       
    47     var self = this;
       
    48     var yCoef        = 2;             // coef for height of 1 tweet 
       
    49     var frameSize     = 5;             // frame size 
       
    50     var margin         = 1;            // marge between frame
       
    51     var lineSize      = this.width;        // timeline pixel width 
       
    52     var nbrframes     = lineSize/frameSize;     // frame numbers
       
    53     var numberOfTweet   = 0;            // number of tweet overide later 
       
    54     var duration      = this.getDuration();      // timescale width 
       
    55     var frameLength   = lineSize / frameSize;    // frame timescale  
       
    56     var timeline;
       
    57     var colors  = new Array("","#1D973D","#036AAE","#CE0A15","#C5A62D","#585858");
       
    58     
       
    59     // array 
       
    60     //var tweets  = new Array();
       
    61     var element = new Array();
       
    62     var cluster = new Array();
       
    63     var frames  = new Array(frameLength);
       
    64     var slices  = new Array();
       
    65     
       
    66     
       
    67     // Classes =======================================================================
       
    68     var Frames = function(){
       
    69       
       
    70       var Myclusters;
       
    71       var x;
       
    72       var y;
       
    73       var width;
       
    74       var height;
       
    75     };
       
    76     Frames = function(json){
       
    77       // make my clusters
       
    78       // ou Frame vide 
       
    79     };
       
    80     Frames.prototype.draw = function(){
       
    81     };
       
    82     Frames.prototype.zoom = function(){
       
    83     };
       
    84     Frames.prototype.inside = function(){
       
    85     };
       
    86     var Clusters = function(){
       
    87       var Object;
       
    88       var yDist;
       
    89       var x;
       
    90       var y;
       
    91       var width;
       
    92       var height;
       
    93     };
       
    94     Clusters = function(json){
       
    95       // make my object
       
    96     };
       
    97     var Tweet = function(){
       
    98     };
       
    99     // Classes =======================================================================
       
   100 
       
   101     // Refactoring (parametere) ************************************************************
       
   102     // color translastion
       
   103     var qTweet_0  =0;
       
   104     var qTweet_Q  =0;
       
   105     var qTweet_REF=0;
       
   106     var qTweet_OK =0;
       
   107     var qTweet_KO =0;
       
   108     function colorTranslation(value){
       
   109       if(value == "Q"){
       
   110         qTweet_Q+=1;
       
   111         return 2;
       
   112       }else if(value =="REF"){
       
   113         qTweet_REF+=1;
       
   114         return 4;
       
   115       }else if(value =="OK"){
       
   116         qTweet_OK+=1;
       
   117         return 1;
       
   118       }else if(value =="KO"){
       
   119         qTweet_KO+=1;
       
   120         return 3;
       
   121       }else if(value ==""){
       
   122         qTweet_0+=1;
       
   123         return 5;
       
   124       }
       
   125     }
       
   126     
       
   127 
       
   128       this._serializer.sync(function(data) { loaded_callback.call(self, data); return; });
       
   129       
       
   130       function loaded_callback (json) {
       
   131       var view_type = this._serializer.getTweets();
       
   132 
       
   133       
       
   134       if (typeof(view_type) === "undefined") {
       
   135         var view_type = this._serializer.getTweetIds()[0];
       
   136         if (typeof(view_type) === "undefined") {
       
   137           // default to guessing if nothing else works.
       
   138           var view = json.views[0];
       
   139           
       
   140           if(typeof(view.annotation_types) !== "undefined") {
       
   141             /* we need to be backward compatible with the old files which used to
       
   142                feature only two lines : Chapitrage and Tweets. We've added a
       
   143                "Contributions" line so we need to discriminate against that */
       
   144             if (view.annotation_types.length === 2 && typeof(this._serializer.getContributions()) === "undefined") {
       
   145               var view_type = view.annotation_types[1];
       
   146             } else {
       
   147               console.log("PolemicWidget: invalid file - minimizing");
       
   148               return;
       
   149             }
       
   150           }      
       
   151         }
       
   152       }
       
   153       
       
   154       // Make and define the Raphael area
       
   155       this.paper = Raphael(document.getElementById(this._id), this._config.width, this._config.height);
       
   156       
       
   157       // event handlers
       
   158       this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) { this.searchHandler(searchString); }));
       
   159       this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.searchFieldClosedHandler));
       
   160       this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.searchFieldClearedHandler));
       
   161       this.selector.mouseleave(IriSP.wrap(this, function() { self.TooltipWidget.hide.call(self.TooltipWidget); }));
       
   162       this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater));
       
   163       this._Popcorn.listen("IriSP.Mediafragment.showAnnotation", IriSP.wrap(this, this.showAnnotation));
       
   164       
       
   165       for(var i = 0; i < json.annotations.length; i++) {
       
   166         var item = json.annotations[i];        
       
   167         var MyTime  = Math.floor(item.begin/duration*lineSize);
       
   168         var Myframe = Math.floor(MyTime/lineSize*frameLength);
       
   169 
       
   170         if (typeof(item.meta) !== "undefined" 
       
   171           && typeof(item.meta["id-ref"]) !== "undefined"
       
   172           && item.meta["id-ref"] === view_type) {
       
   173             
       
   174             var MyTJson = {},
       
   175                 _source = IriSP.get_aliased(item.meta, ['dc:source', 'source']);
       
   176             if (_source !== null) {
       
   177               var MyTJson = JSON.parse(_source['content']);
       
   178             }
       
   179             
       
   180             if (item.content['polemics'] != undefined 
       
   181             && item.content['polemics'][0] != null) {
       
   182             
       
   183               // a tweet can have many polemics at the same time.
       
   184               for(var j=0; j<item.content['polemics'].length; j++){
       
   185                   
       
   186                   this.tweets[numberOfTweet] = {
       
   187                         id:i,
       
   188                         qualification:colorTranslation(item.content['polemics'][j]),
       
   189                         yIndicator:MyTime,
       
   190                         yframe:Myframe,
       
   191                         title:item.content['title'],
       
   192                         timeframe:item.begin,
       
   193                         userId: MyTJson.id,
       
   194                         userScreenName: MyTJson.screen_name,
       
   195                         tsource:MyTJson,
       
   196                         cinecast_id: item.id
       
   197                         };
       
   198                   numberOfTweet+=1;
       
   199                   
       
   200               }
       
   201           }
       
   202           else {
       
   203             this.tweets[numberOfTweet] = {
       
   204                   id:i,
       
   205                   qualification:colorTranslation(""),
       
   206                   yIndicator:MyTime,
       
   207                   yframe:Myframe,
       
   208                   title:item.content['title'],
       
   209                   timeframe:item.begin,
       
   210                   userId: MyTJson.id,
       
   211                   userScreenName: MyTJson.screen_name,
       
   212                   tsource:MyTJson,
       
   213                   cinecast_id: item.id
       
   214             };
       
   215             numberOfTweet+=1;
       
   216           }
       
   217           
       
   218         } 
       
   219       };  
       
   220       
       
   221        DrawTweets.call (this); // FIXME: ugly.
       
   222        
       
   223       };      
       
   224 
       
   225     // tweet Drawing (in raphael) 
       
   226     function DrawTweets (){
       
   227     // GROUPES TWEET ============================================
       
   228     // Count nbr of cluster and tweet in a frame an save int in "frames"
       
   229       numberOfTweet = this.tweets.length;
       
   230       for(var i=0; i<nbrframes; i++) {  
       
   231         for(var j=0; j<numberOfTweet; j++) {  
       
   232         
       
   233           if (i==this.tweets[j].yframe){
       
   234             
       
   235             var k = this.tweets[j].qualification;
       
   236             
       
   237             // make array for frame cluster
       
   238             if(frames[i]==undefined){
       
   239               frames[i] = {id:i,
       
   240                      qualifVol:new Array(),
       
   241                      mytweetsID:new Array()
       
   242                     };
       
   243             }
       
   244             // add my tweet to frame
       
   245             frames[i].mytweetsID.push(this.tweets[j]);
       
   246             
       
   247             // count opinion by frame
       
   248             if( frames[i].qualifVol[k] == undefined){
       
   249               frames[i].qualifVol[k] = 1;
       
   250             }else{
       
   251               frames[i].qualifVol[k] += 1;
       
   252             }
       
   253             
       
   254           }
       
   255         }
       
   256       }
       
   257     
       
   258     // GROUPES TWEET ============================================    
       
   259     // max of tweet by Frame 
       
   260       var max = 0; 
       
   261       for(var i = 0; i < nbrframes; i++) {
       
   262         var moy  = 0;
       
   263         for (var j = 0; j < 6; j++) {    
       
   264           if (frames[i] != undefined) {
       
   265             if (frames[i].qualifVol[j] != undefined) {
       
   266               moy += frames[i].qualifVol[j];
       
   267             }
       
   268           }
       
   269         }
       
   270         
       
   271         if (moy > max) {
       
   272           max = moy;
       
   273         }
       
   274       }
       
   275     
       
   276       var tweetDrawed = new Array();
       
   277       var TweetHeight = 5;
       
   278       var newHeight = TweetHeight * max + 10;
       
   279 
       
   280       
       
   281       if (newHeight > this.height) {
       
   282         this.paper.setSize(this.width, newHeight);
       
   283         this.height = newHeight;
       
   284         console.log("resizeing");
       
   285       }
       
   286       
       
   287   
       
   288       // DRAW  TWEETS ============================================
       
   289       for(var i = 0; i < nbrframes; i++) {
       
   290         var addEheight = 5;
       
   291         if (frames[i] != undefined){                
       
   292           // by type 
       
   293           
       
   294           for (var j = 6; j > -1; j--) {
       
   295             if (frames[i].qualifVol[j] != undefined) {
       
   296               // show tweet by type 
       
   297               for (var k = 0; k < frames[i].mytweetsID.length; k++) {
       
   298               
       
   299                 if (frames[i].mytweetsID[k].qualification == j) {                
       
   300                   var x = i * frameSize;
       
   301                   var y = this.height - addEheight;
       
   302                   
       
   303                   if (this.yMax > y) {
       
   304                     this.yMax = y;
       
   305                   }
       
   306                   
       
   307                   /* some tweets seem to be duplicated - so we make a check before
       
   308                      creating a new rect */
       
   309                   if (this.svgElements.hasOwnProperty(frames[i].mytweetsID[k].cinecast_id))
       
   310                     continue;
       
   311                   
       
   312                   var e = this.paper.rect(x, y, frameSize - margin, TweetHeight /* height */)
       
   313                                     .attr({stroke:"#00","stroke-width":0.1,  fill: colors[j]});  
       
   314                   
       
   315                   addEheight += TweetHeight;
       
   316                   
       
   317                   /* stick a lot of things into e because that's the easiest way
       
   318                      to do it */
       
   319                   e.color = colors[j];
       
   320                   e.time = frames[i].mytweetsID[k].timeframe;
       
   321                   e.title = frames[i].mytweetsID[k].title;
       
   322                   e.id = frames[i].mytweetsID[k].cinecast_id;
       
   323                   this.svgElements[e.id] = e;
       
   324                   
       
   325                   IriSP.jQuery(e.node).mouseenter(function(element) { return function (_e) {                    
       
   326                         self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), element.attrs.x + element.attrs.width / 2, element.attrs.y - 2);
       
   327                         element.displayed = true;
       
   328                         self._Popcorn.trigger("IriSP.TraceWidget.MouseEvents", {
       
   329                             "widget" : "StackGraphWidget",
       
   330                             "type": "mousemove",
       
   331                             "x": _e.pageX,
       
   332                             "y": _e.pageY,
       
   333                             "annotation_id": element.id
       
   334                         });
       
   335                   }}(e)).mousedown(function(element) { return function () {                    
       
   336                     self._Popcorn.currentTime(element.time/1000);
       
   337                     self._Popcorn.trigger("IriSP.PolemicTweet.click", element.id); 
       
   338                     }
       
   339                   }(e));                  
       
   340                   
       
   341                   IriSP.jQuery(e.node).attr('id', 't' + k + '');
       
   342                   IriSP.jQuery(e.node).attr('title', frames[i].mytweetsID[k].title);
       
   343                   IriSP.jQuery(e.node).attr('begin',  frames[i].mytweetsID[k].timeframe);                  
       
   344                 }
       
   345               }
       
   346             }
       
   347           }
       
   348         }
       
   349 
       
   350       }    
       
   351       // DRAW UI :: resize border and bgd      
       
   352       this.paperBackground = this.paper.rect(0, 0, this.width, this.height).attr({fill:"#F8F8F8","stroke-width":0.1,opacity: 1});  
       
   353 
       
   354       // outer borders
       
   355       this.outerBorders   = [];
       
   356       this.outerBorders.push(this.paper.rect(0, this.height - 1, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1}));  
       
   357       this.outerBorders.push(this.paper.rect(0, 0, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1}));  
       
   358 
       
   359       // inner borders
       
   360       this.innerBorders   = [];
       
   361       this.innerBorders.push(this.paper.rect(1, this.height - 2, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
       
   362       this.innerBorders.push(this.paper.rect(1, 1, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
       
   363       this.innerBorders.push(this.paper.rect(1, 1, 1, this.height - 2).attr({fill:"#d0d1d1",stroke: "none",opacity: 0.8}));  
       
   364       this.innerBorders.push(this.paper.rect(this.width - 2, 1, 1, this.height - 2).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
       
   365 
       
   366 
       
   367 
       
   368       this.paperSlider   = this.paper.rect(0, 0, 0, this.height).attr({fill:"#D4D5D5", stroke: "none", opacity: 1});
       
   369       
       
   370       // the small white line displayed over the slider.
       
   371       this.sliderTip = this.paper.rect(0, 0, 1, this.height).attr({fill:"#fc00ff", stroke: "none", opacity: 1});
       
   372       // decalage 
       
   373       // tweetSelection = this.paper.rect(-100,-100,5,5).attr({fill:"#fff",stroke: "none",opacity: 1});  
       
   374       
       
   375       
       
   376       this.paperSlider.toBack();
       
   377       this.paperBackground.toBack();
       
   378       this.sliderTip.toFront();
       
   379     }
       
   380     
       
   381 
       
   382 }
       
   383 
       
   384 /** update the positionMarker as time passes */
       
   385 IriSP.PolemicWidget.prototype.sliderUpdater = function() {
       
   386 
       
   387     var time = +this._Popcorn.currentTime();
       
   388     var duration = this.getDuration();
       
   389     
       
   390     this.paperSlider.attr("width", time * (this.width / (duration / 1000)));
       
   391         
       
   392     this.sliderTip.attr("x", time * (this.width / (duration / 1000)));
       
   393 };
       
   394 
       
   395 /** reacts to IriSP.search events */    
       
   396 IriSP.PolemicWidget.prototype.searchHandler = function(searchString) {
       
   397   if (searchString == "")
       
   398     return;
       
   399 
       
   400   var matches = this._serializer.searchTweetsOccurences(searchString);
       
   401 
       
   402   if (IriSP.countProperties(matches) > 0) {
       
   403     this._Popcorn.trigger("IriSP.search.matchFound");
       
   404   } else {
       
   405     this._Popcorn.trigger("IriSP.search.noMatchFound");
       
   406   }
       
   407 
       
   408   
       
   409   // decrease the opacity of the other elements.
       
   410   for (var id in this.svgElements) {
       
   411     var e = this.svgElements[id];
       
   412     e.attr({fill: e.color, opacity: 0.4});   
       
   413   }
       
   414   
       
   415 
       
   416   for (var id in matches) {    
       
   417     if (this.svgElements.hasOwnProperty(id)) {
       
   418       var e = this.svgElements[id];
       
   419       this.svgElements[id].attr({fill: "#fc00ff", opacity: 1});
       
   420     }
       
   421   }
       
   422 
       
   423   this.oldSearchMatches = matches;
       
   424 };
       
   425 
       
   426 /** reacts to IriSP.search.cleared messages */
       
   427 IriSP.PolemicWidget.prototype.searchFieldClearedHandler = function() {
       
   428   for (var id in this.svgElements) {
       
   429     var e = this.svgElements[id];
       
   430     e.attr({fill: e.color, opacity: 1});
       
   431   }
       
   432 };
       
   433 
       
   434 /** reacts to IriSP.search.closed messages by clearing the highlighted elements */
       
   435 IriSP.PolemicWidget.prototype.searchFieldClosedHandler = function() {
       
   436   for (var id in this.svgElements) {
       
   437     var e = this.svgElements[id];
       
   438     e.attr({fill: e.color, opacity: 1});
       
   439   }
       
   440  
       
   441 };
       
   442    
       
   443 IriSP.PolemicWidget.prototype.showAnnotation = function(id) {
       
   444   if (this.svgElements.hasOwnProperty(id)) {
       
   445     var e = this.svgElements[id];
       
   446     this.TooltipWidget.show(e.title, e.attr("fill"), e.x - 103, e.y - 160);
       
   447   }
       
   448 };