src/js/widgets/polemicWidget.js
branchnew-model
changeset 874 38b65761a7d5
parent 842 4ae2247a59f4
--- a/src/js/widgets/polemicWidget.js	Thu Apr 19 19:20:41 2012 +0200
+++ b/src/js/widgets/polemicWidget.js	Fri Apr 20 19:13:11 2012 +0200
@@ -1,448 +1,178 @@
-/* 
- *   
- *  Copyright 2010 Institut de recherche et d'innovation 
- *  contributor(s) : Samuel Huron 
- *   
- *  contact@iri.centrepompidou.fr
- *  http://www.iri.centrepompidou.fr 
- *   
- *  This software is a computer program whose purpose is to show and add annotations on a video .
- *  This software is governed by the CeCILL-C license under French law and
- *  abiding by the rules of distribution of free software. You can  use, 
- *  modify and/ or redistribute the software under the terms of the CeCILL-C
- *  license as circulated by CEA, CNRS and INRIA at the following URL
- *  "http://www.cecill.info". 
- *  
- *  The fact that you are presently reading this means that you have had
- *  knowledge of the CeCILL-C license and that you accept its terms.
-*/
-// CHART TIMELINE / VERSION PROTOTYPE  ::
-
-/** the polemic widget */
-IriSP.PolemicWidget = function(Popcorn, config, Serializer) {
-  IriSP.Widget.call(this, Popcorn, config, Serializer);
- 
-  this.userPol    = new Array();
-  this.userNoPol  = new Array();
-  this.userst      = new Array();
-  this.numberOfTweet = 0;
-  this.Users;
-  this.TweetPolemic;
-  this.yMax        = this.height; 
-  this.PaperSlider;
-  this.heightOfChart;
-  this.tweets  = new Array();
-  this.svgElements = {};
-  
-  this.oldSearchMatches = [];
+IriSP.PolemicWidget = function(player, config) {
+    IriSP.Widget.call(this, player, config);
+    this.bindPopcorn("IriSP.search", "searchHandler");
+    this.bindPopcorn("IriSP.search.closed", "searchHandler");
+    this.bindPopcorn("IriSP.search.cleared", "searchHandler");
+    this.bindPopcorn("timeupdate", "onTimeupdate");
+    this.sliceCount = Math.floor( this.width / this.element_width );
+    this.$zone = IriSP.jQuery('<div>');
+    this.$.append(this.$zone);
 };
 
 IriSP.PolemicWidget.prototype = new IriSP.Widget();
-  
-IriSP.PolemicWidget.prototype.draw = function() {
-  
-    // variable 
-    // yMax
-    
-    var self = this;
-    var yCoef        = 2;             // coef for height of 1 tweet 
-    var frameSize     = 5;             // frame size 
-    var margin         = 1;            // marge between frame
-    var lineSize      = this.width;        // timeline pixel width 
-    var nbrframes     = lineSize/frameSize;     // frame numbers
-    var numberOfTweet   = 0;            // number of tweet overide later 
-    var duration      = this.getDuration();      // timescale width 
-    var frameLength   = lineSize / frameSize;    // frame timescale  
-    var timeline;
-    var colors  = new Array("","#1D973D","#036AAE","#CE0A15","#C5A62D","#585858");
-    
-    // array 
-    //var tweets  = new Array();
-    var element = new Array();
-    var cluster = new Array();
-    var frames  = new Array(frameLength);
-    var slices  = new Array();
-    
-    
-    // Classes =======================================================================
-    var Frames = function(){
-      
-      var Myclusters;
-      var x;
-      var y;
-      var width;
-      var height;
-    };
-    Frames = function(json){
-      // make my clusters
-      // ou Frame vide 
-    };
-    Frames.prototype.draw = function(){
-    };
-    Frames.prototype.zoom = function(){
-    };
-    Frames.prototype.inside = function(){
-    };
-    var Clusters = function(){
-      var Object;
-      var yDist;
-      var x;
-      var y;
-      var width;
-      var height;
-    };
-    Clusters = function(json){
-      // make my object
-    };
-    var Tweet = function(){
-    };
-    // Classes =======================================================================
 
-    // Refactoring (parametere) ************************************************************
-    // color translastion
-    var qTweet_0  =0;
-    var qTweet_Q  =0;
-    var qTweet_REF=0;
-    var qTweet_OK =0;
-    var qTweet_KO =0;
-    function colorTranslation(value){
-      if(value == "Q"){
-        qTweet_Q+=1;
-        return 2;
-      }else if(value =="REF"){
-        qTweet_REF+=1;
-        return 4;
-      }else if(value =="OK"){
-        qTweet_OK+=1;
-        return 1;
-      }else if(value =="KO"){
-        qTweet_KO+=1;
-        return 3;
-      }else if(value ==""){
-        qTweet_0+=1;
-        return 5;
-      }
+IriSP.PolemicWidget.prototype.searchHandler = function(searchString) {
+    this.searchString = typeof searchString !== "undefined" ? searchString : '';
+    var _found = 0,
+        _re = IriSP.Model.regexpFromTextOrArray(searchString)
+        _this = this;
+    this.$tweets.each(function() {
+        var _el = IriSP.jQuery(this);
+        if (_this.searchString) {
+            if (_re.test(_el.attr("tweet-title"))) {
+                _el.css({
+                    "background" : _this.foundcolor,
+                    "opacity" : 1
+                });
+                _found++;
+            } else {
+                _el.css({
+                    "background" : _el.attr("polemic-color"),
+                    "opacity" : .5
+                });
+            }
+        } else {
+            _el.css({
+                "background" : _el.attr("polemic-color"),
+                "opacity" : 1
+            });
+        }
+    });
+    if (this.searchString) {
+        if (_found) {
+            this.player.popcorn.trigger("IriSP.search.matchFound");
+        } else {
+            this.player.popcorn.trigger("IriSP.search.noMatchFound");
+        }
     }
-    
-
-      this._serializer.sync(function(data) { loaded_callback.call(self, data); return; });
-      
-      function loaded_callback (json) {
-      var view_type = this._serializer.getTweets();
+}
 
-      
-      if (typeof(view_type) === "undefined") {
-        var view_type = this._serializer.getTweetIds()[0];
-        if (typeof(view_type) === "undefined") {
-          // default to guessing if nothing else works.
-          var view = json.views[0];
-          
-          if(typeof(view.annotation_types) !== "undefined") {
-            /* we need to be backward compatible with the old files which used to
-               feature only two lines : Chapitrage and Tweets. We've added a
-               "Contributions" line so we need to discriminate against that */
-            if (view.annotation_types.length === 2 && typeof(this._serializer.getContributions()) === "undefined") {
-              var view_type = view.annotation_types[1];
-            } else {
-              console.log("PolemicWidget: invalid file - minimizing");
-              return;
-            }
-          }      
-        }
-      }
-      
-      // Make and define the Raphael area
-      this.paper = Raphael(document.getElementById(this._id), this._config.width, this._config.height);
-      
-      // event handlers
-      this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) { this.searchHandler(searchString); }));
-      this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.searchFieldClosedHandler));
-      this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.searchFieldClearedHandler));
-      this.selector.mouseleave(IriSP.wrap(this, function() { self.TooltipWidget.hide.call(self.TooltipWidget); }));
-      this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater));
-      this._Popcorn.listen("IriSP.Mediafragment.showAnnotation", IriSP.wrap(this, this.showAnnotation));
-      
-      for(var i = 0; i < json.annotations.length; i++) {
-        var item = json.annotations[i];        
-        var MyTime  = Math.floor(item.begin/duration*lineSize);
-        var Myframe = Math.floor(MyTime/lineSize*frameLength);
-
-        if (typeof(item.meta) !== "undefined" 
-          && typeof(item.meta["id-ref"]) !== "undefined"
-          && item.meta["id-ref"] === view_type) {
-            
-            var MyTJson = {},
-                _source = IriSP.get_aliased(item.meta, ['dc:source', 'source']);
-            if (_source !== null) {
-              var MyTJson = JSON.parse(_source['content']);
+IriSP.PolemicWidget.prototype.draw = function() {
+    var _slices = [],
+        _duration = this.source.getDuration(),
+        _max = 0,
+        _list = this.annotation_type ? this.source.getAnnotationsByTypeTitle(this.annotation_type) : this.source.getAnnotations();
+    
+    for (var _i = 0; _i < this.sliceCount; _i++) {
+        var _begin = new IriSP.Model.Time(_i*_duration/this.sliceCount),
+            _end = new IriSP.Model.Time((_i+1)*_duration/this.sliceCount),
+            _count = 0,
+            _res = {
+                annotations : _list.filter(function(_annotation) {
+                    return _annotation.begin >= _begin && _annotation.end < _end;
+                }),
+                polemicStacks : []
             }
             
-            if (item.content['polemics'] != undefined 
-            && item.content['polemics'][0] != null) {
-            
-              // a tweet can have many polemics at the same time.
-              for(var j=0; j<item.content['polemics'].length; j++){
-                  
-                  this.tweets[numberOfTweet] = {
-                        id:i,
-                        qualification:colorTranslation(item.content['polemics'][j]),
-                        yIndicator:MyTime,
-                        yframe:Myframe,
-                        title:item.content['title'],
-                        timeframe:item.begin,
-                        userId: MyTJson.id,
-                        userScreenName: MyTJson.screen_name,
-                        tsource:MyTJson,
-                        cinecast_id: item.id
-                        };
-                  numberOfTweet+=1;
-                  
-              }
-          }
-          else {
-            this.tweets[numberOfTweet] = {
-                  id:i,
-                  qualification:colorTranslation(""),
-                  yIndicator:MyTime,
-                  yframe:Myframe,
-                  title:item.content['title'],
-                  timeframe:item.begin,
-                  userId: MyTJson.id,
-                  userScreenName: MyTJson.screen_name,
-                  tsource:MyTJson,
-                  cinecast_id: item.id
-            };
-            numberOfTweet+=1;
-          }
-          
-        } 
-      };  
-      
-       DrawTweets.call (this); // FIXME: ugly.
-       
-      };      
-
-    // tweet Drawing (in raphael) 
-    function DrawTweets (){
-    // GROUPES TWEET ============================================
-    // Count nbr of cluster and tweet in a frame an save int in "frames"
-      numberOfTweet = this.tweets.length;
-      for(var i=0; i<nbrframes; i++) {  
-        for(var j=0; j<numberOfTweet; j++) {  
-        
-          if (i==this.tweets[j].yframe){
-            
-            var k = this.tweets[j].qualification;
-            
-            // make array for frame cluster
-            if(frames[i]==undefined){
-              frames[i] = {id:i,
-                     qualifVol:new Array(),
-                     mytweetsID:new Array()
-                    };
-            }
-            // add my tweet to frame
-            frames[i].mytweetsID.push(this.tweets[j]);
-            
-            // count opinion by frame
-            if( frames[i].qualifVol[k] == undefined){
-              frames[i].qualifVol[k] = 1;
-            }else{
-              frames[i].qualifVol[k] += 1;
-            }
-            
-          }
+        for (var _j = 0; _j < this.tags.length; _j++) {
+            var _polemic = _res.annotations.searchByDescription(this.tags[_j].keywords);
+            _count += _polemic.length;
+            _res.polemicStacks.push(_polemic);
+        }
+        for (var _j = 0; _j < this.tags.length; _j++) {
+            _res.annotations.removeElements(_res.polemicStacks[_j]);
         }
-      }
-    
-    // GROUPES TWEET ============================================    
-    // max of tweet by Frame 
-      var max = 0; 
-      for(var i = 0; i < nbrframes; i++) {
-        var moy  = 0;
-        for (var j = 0; j < 6; j++) {    
-          if (frames[i] != undefined) {
-            if (frames[i].qualifVol[j] != undefined) {
-              moy += frames[i].qualifVol[j];
-            }
-          }
-        }
-        
-        if (moy > max) {
-          max = moy;
-        }
-      }
+        _count += _res.annotations.length;
+        _max = Math.max(_max, _count);
+        _slices.push(_res);
+    }
+    this.height = (_max ? (_max + 2) * this.element_height : 0);
+    this.$zone.css({
+        width: this.width + "px",
+        height: this.height + "px",
+        position: "relative"
+    });
     
-      var tweetDrawed = new Array();
-      var TweetHeight = 5;
-      var newHeight = TweetHeight * max + 10;
-
-      
-      if (newHeight > this.height) {
-        this.paper.setSize(this.width, newHeight);
-        this.height = newHeight;
-        console.log("resizeing");
-      }
-      
-  
-      // DRAW  TWEETS ============================================
-      for(var i = 0; i < nbrframes; i++) {
-        var addEheight = 5;
-        if (frames[i] != undefined){                
-          // by type 
-          
-          for (var j = 6; j > -1; j--) {
-            if (frames[i].qualifVol[j] != undefined) {
-              // show tweet by type 
-              for (var k = 0; k < frames[i].mytweetsID.length; k++) {
-              
-                if (frames[i].mytweetsID[k].qualification == j) {                
-                  var x = i * frameSize;
-                  var y = this.height - addEheight;
-                  
-                  if (this.yMax > y) {
-                    this.yMax = y;
-                  }
-                  
-                  /* some tweets seem to be duplicated - so we make a check before
-                     creating a new rect */
-                  if (this.svgElements.hasOwnProperty(frames[i].mytweetsID[k].cinecast_id))
-                    continue;
-                  
-                  var e = this.paper.rect(x, y, frameSize - margin, TweetHeight /* height */)
-                                    .attr({stroke:"#00","stroke-width":0.1,  fill: colors[j]});  
-                  
-                  addEheight += TweetHeight;
-                  
-                  /* stick a lot of things into e because that's the easiest way
-                     to do it */
-                  e.color = colors[j];
-                  e.time = frames[i].mytweetsID[k].timeframe;
-                  e.title = frames[i].mytweetsID[k].title;
-                  e.id = frames[i].mytweetsID[k].cinecast_id;
-                  this.svgElements[e.id] = e;
-                  
-                  IriSP.jQuery(e.node).mouseenter(function(element) { return function (_e) {                    
-                        self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), element.attrs.x + element.attrs.width / 2, element.attrs.y - 2);
-                        element.displayed = true;
-                        self._Popcorn.trigger("IriSP.TraceWidget.MouseEvents", {
-                            "widget" : "StackGraphWidget",
-                            "type": "mousemove",
-                            "x": _e.pageX,
-                            "y": _e.pageY,
-                            "annotation_id": element.id
-                        });
-                  }}(e)).mousedown(function(element) { return function () {                    
-                    self._Popcorn.currentTime(element.time/1000);
-                    self._Popcorn.trigger("IriSP.PolemicTweet.click", element.id); 
-                    }
-                  }(e));                  
-                  
-                  IriSP.jQuery(e.node).attr('id', 't' + k + '');
-                  IriSP.jQuery(e.node).attr('title', frames[i].mytweetsID[k].title);
-                  IriSP.jQuery(e.node).attr('begin',  frames[i].mytweetsID[k].timeframe);                  
-                }
-              }
-            }
-          }
-        }
-
-      }    
-      // DRAW UI :: resize border and bgd      
-      this.paperBackground = this.paper.rect(0, 0, this.width, this.height).attr({fill:"#F8F8F8","stroke-width":0.1,opacity: 1});  
-
-      // outer borders
-      this.outerBorders   = [];
-      this.outerBorders.push(this.paper.rect(0, this.height - 1, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1}));  
-      this.outerBorders.push(this.paper.rect(0, 0, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1}));  
-
-      // inner borders
-      this.innerBorders   = [];
-      this.innerBorders.push(this.paper.rect(1, this.height - 2, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
-      this.innerBorders.push(this.paper.rect(1, 1, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
-      this.innerBorders.push(this.paper.rect(1, 1, 1, this.height - 2).attr({fill:"#d0d1d1",stroke: "none",opacity: 0.8}));  
-      this.innerBorders.push(this.paper.rect(this.width - 2, 1, 1, this.height - 2).attr({fill:"#efefef",stroke: "none",opacity: 1}));  
-
-
-
-      this.paperSlider   = this.paper.rect(0, 0, 0, this.height).attr({fill:"#D4D5D5", stroke: "none", opacity: 1});
-      
-      // the small white line displayed over the slider.
-      this.sliderTip = this.paper.rect(0, 0, 1, this.height).attr({fill:"#fc00ff", stroke: "none", opacity: 1});
-      // decalage 
-      // tweetSelection = this.paper.rect(-100,-100,5,5).attr({fill:"#fff",stroke: "none",opacity: 1});  
-      
-      
-      this.paperSlider.toBack();
-      this.paperBackground.toBack();
-      this.sliderTip.toFront();
+    this.$elapsed = IriSP.jQuery('<div>')
+        .css({
+            background: '#cccccc',
+            position: "absolute",
+            top: 0,
+            left: 0,
+            width: 0,
+            height: "100%"
+        });
+        
+    this.$zone.append(this.$elapsed);
+    
+    var _x = 0,
+        _this = this;
+    
+    function displayElement(_x, _y, _color, _id, _title) {
+        var _el = IriSP.jQuery('<div>')
+            .attr({
+                "tweet-title" : _title,
+                "pos-x" : Math.floor(_x + (_this.element_width - 1) / 2),
+                "pos-y" : _y,
+                "polemic-color" : _color,
+                "annotation-id" : _id
+            })
+            .css({
+                position: "absolute",
+                width: (_this.element_width-1) + "px",
+                height: _this.element_height + "px",
+                left: _x + "px",
+                top: _y + "px",
+                background: _color
+            })
+            .addClass("Ldt-Polemic-TweetDiv");
+        _this.$zone.append(_el);
+        return _el;
     }
     
-
+    IriSP._(_slices).forEach(function(_slice) {
+        var _y = _this.height;
+        _slice.annotations.forEach(function(_annotation) {
+            _y -= _this.element_height;
+            displayElement(_x, _y, _this.defaultcolor, _annotation.namespacedId.name, _annotation.title);
+        });
+        IriSP._(_slice.polemicStacks).forEach(function(_annotations, _j) {
+            var _color = _this.tags[_j].color;
+            _annotations.forEach(function(_annotation) {
+                _y -= _this.element_height;
+                displayElement(_x, _y, _color, _annotation.namespacedId.name, _annotation.title);
+            });
+        });
+        _x += _this.element_width;
+    });
+    
+    this.$tweets = this.$.find(".Ldt-Polemic-TweetDiv");
+    
+    this.$position = IriSP.jQuery('<div>')
+        .css({
+            background: '#fc00ff',
+            position: "absolute",
+            top: 0,
+            left: "-1px",
+            width: "2px",
+            height: "100%"
+        });
+        
+    this.$zone.append(this.$position);
+    
+    this.$tweets
+        .mouseover(function() {
+            var _el = IriSP.jQuery(this);
+            _this.TooltipWidget.show(_el.attr("pos-x"), _el.attr("pos-y"), _el.attr("tweet-title"), _el.attr("polemic-color"));
+        })
+        .mouseout(function() {
+            _this.TooltipWidget.hide();
+        });
+    
+    //TODO: Display Tweet in Tweet Widget on click
+    
+    this.$zone.click(function(_e) {
+        var _x = _e.pageX - _this.$zone.offset().left;
+        _this.player.popcorn.currentTime(_this.source.getDuration().getSeconds() * _x / _this.width);
+    });
 }
 
-/** update the positionMarker as time passes */
-IriSP.PolemicWidget.prototype.sliderUpdater = function() {
-
-    var time = +this._Popcorn.currentTime();
-    var duration = this.getDuration();
-    
-    this.paperSlider.attr("width", time * (this.width / (duration / 1000)));
-        
-    this.sliderTip.attr("x", time * (this.width / (duration / 1000)));
-};
-
-/** reacts to IriSP.search events */    
-IriSP.PolemicWidget.prototype.searchHandler = function(searchString) {
-  if (searchString == "")
-    return;
-
-  var matches = this._serializer.searchTweetsOccurences(searchString);
-
-  if (IriSP.countProperties(matches) > 0) {
-    this._Popcorn.trigger("IriSP.search.matchFound");
-  } else {
-    this._Popcorn.trigger("IriSP.search.noMatchFound");
-  }
-
-  
-  // decrease the opacity of the other elements.
-  for (var id in this.svgElements) {
-    var e = this.svgElements[id];
-    e.attr({fill: e.color, opacity: 0.4});   
-  }
-  
-
-  for (var id in matches) {    
-    if (this.svgElements.hasOwnProperty(id)) {
-      var e = this.svgElements[id];
-      this.svgElements[id].attr({fill: "#fc00ff", opacity: 1});
-    }
-  }
-
-  this.oldSearchMatches = matches;
-};
-
-/** reacts to IriSP.search.cleared messages */
-IriSP.PolemicWidget.prototype.searchFieldClearedHandler = function() {
-  for (var id in this.svgElements) {
-    var e = this.svgElements[id];
-    e.attr({fill: e.color, opacity: 1});
-  }
-};
-
-/** reacts to IriSP.search.closed messages by clearing the highlighted elements */
-IriSP.PolemicWidget.prototype.searchFieldClosedHandler = function() {
-  for (var id in this.svgElements) {
-    var e = this.svgElements[id];
-    e.attr({fill: e.color, opacity: 1});
-  }
- 
-};
-   
-IriSP.PolemicWidget.prototype.showAnnotation = function(id) {
-  if (this.svgElements.hasOwnProperty(id)) {
-    var e = this.svgElements[id];
-    this.TooltipWidget.show(e.title, e.attr("fill"), e.x - 103, e.y - 160);
-  }
-};   
+IriSP.PolemicWidget.prototype.onTimeupdate = function() {
+    var _x = Math.floor( this.width * this.player.popcorn.currentTime() / this.source.getDuration().getSeconds());
+    this.$elapsed.css({
+        width:  _x + "px"
+    });
+    this.$position.css({
+        left: (_x - 1) + "px"
+    })
+}