src/js/widgets/stackGraphWidget.js
branchpopcorn-port
changeset 660 78f392af62db
parent 657 138160f52f14
child 661 48c1beea7b1c
equal deleted inserted replaced
659:501efe401eea 660:78f392af62db
       
     1 IriSP.StackGraphWidget = function(Popcorn, config, Serializer) {
       
     2   IriSP.Widget.call(this, Popcorn, config, Serializer);
       
     3 }
       
     4 
       
     5 IriSP.StackGraphWidget.prototype = new IriSP.Widget();
       
     6 
       
     7 IriSP.StackGraphWidget.prototype.draw = function() {
       
     8     var _defaultTags = [
       
     9             {
       
    10                 "keywords" : [ "++" ],
       
    11                 "description" : "positif",
       
    12                 "color" : "#1D973D",
       
    13             },
       
    14             {
       
    15                 "keywords" : [ "--" ],
       
    16                 "description" : "negatif",
       
    17                 "color" : "#CE0A15",
       
    18             },
       
    19             {
       
    20                 "keywords" : [ "==" ],
       
    21                 "description" : "reference",
       
    22                 "color" : "#C5A62D",   
       
    23             },
       
    24             {
       
    25                 "keywords" : [ "??" ],
       
    26                 "description" : "question",
       
    27                 "color" : "#036AAE",
       
    28             },
       
    29         ],
       
    30         _defaultDefColor = "#585858";
       
    31     this.height = (this._config.height ? this._config.height : 50);
       
    32     this.width = this.selector.width();
       
    33     this.isStreamGraph = (this._config.streamgraph ? this._config.streamgraph : false);
       
    34     this.sliceCount = (this._config.slices ? this._config.slices : ~~(this.width/(this.isStreamGraph ? 20 : 5)));
       
    35     this.tagconf = (this._config.tags
       
    36         ? this._config.tags
       
    37         : _defaultTags);
       
    38     IriSP._(this.tagconf).each(function(_a) {
       
    39         _a.regexp = new RegExp(_a.keywords.map(function(_k) {
       
    40             return _k.replace(/([\W])/gm,'\\$1');
       
    41         }).join("|"),"im")
       
    42     });
       
    43     this.defaultcolorconf = (this._config.defaultcolor
       
    44         ? this._config.defaultcolor
       
    45         : _defaultDefColor);
       
    46     this.paper = new Raphael(this.selector[0], this.width, this.height);
       
    47     this.groups = [];
       
    48     this.duration = this._serializer.currentMedia().meta["dc:duration"];
       
    49     
       
    50     var _annotationType = this._serializer.getTweets(),
       
    51         _sliceDuration = ~~ ( this.duration / this.sliceCount),
       
    52         _annotations = IriSP._(this._serializer._data.annotations).filter(function(_a) {
       
    53             return ( _a.meta && _a.meta["id-ref"] && ( _a.meta["id-ref"] == _annotationType ) );
       
    54         }),
       
    55         _groupedAnnotations = IriSP._(_annotations).groupBy(function(_a) {
       
    56             return ~~ (_a.begin / _sliceDuration);
       
    57         }),
       
    58         _max = IriSP._(_groupedAnnotations).max(function(_g) {
       
    59             return _g.length
       
    60         }).length,
       
    61         _scale = this.height / _max,
       
    62         _width = this.width / this.sliceCount;
       
    63     
       
    64     
       
    65     var _paths = this.tagconf.map(function() {
       
    66         return [];
       
    67     });
       
    68     _paths.push([]);
       
    69     
       
    70     for (var i = 0; i < this.sliceCount; i++) {
       
    71         var _group = _groupedAnnotations[i];
       
    72         if (_group) {
       
    73             var _vol = this.tagconf.map(function() {
       
    74                 return 0;
       
    75             });
       
    76             for (var j = 0; j < _group.length; j++){
       
    77                 var _txt = _group[j].content.description;
       
    78                 var _tags = this.tagconf.map(function(_tag) {
       
    79                         return (_txt.search(_tag.regexp) == -1 ? 0 : 1)
       
    80                     }),
       
    81                     _nbtags = _tags.reduce(function(_a,_b) {
       
    82                         return _a + _b;
       
    83                     }, 0);
       
    84                 if (_nbtags) {
       
    85                     IriSP._(_tags).each(function(_v, _k) {
       
    86                         _vol[_k] += (_v / _nbtags);
       
    87                     });
       
    88                 }
       
    89             }
       
    90             var _nbtags = _vol.reduce(function(_a,_b) {
       
    91                     return _a + _b;
       
    92                 }, 0),
       
    93                 _nbneutre = _group.length - _nbtags,
       
    94                 _h = _nbneutre * _scale,
       
    95                 _base = this.height - _h;
       
    96             if (!this.isStreamGraph) {
       
    97                 this.paper.rect(i * _width, _base, _width - 1, _h ).attr({
       
    98                     "stroke" : "none",
       
    99                     "fill" : this.defaultcolorconf,
       
   100                 });
       
   101             }
       
   102            _paths[0].push(_base);
       
   103             for (var j = 0; j < this.tagconf.length; j++) {
       
   104                 _h = _vol[j] * _scale;
       
   105                 _base = _base - _h;
       
   106                 if (!this.isStreamGraph) {
       
   107                     this.paper.rect(i * _width, _base, _width - 1, _h ).attr({
       
   108                         "stroke" : "none",
       
   109                         "fill" : this.tagconf[j].color,
       
   110                     });
       
   111                 }
       
   112                 _paths[j+1].push(_base);
       
   113             }
       
   114             this.groups.push(_vol.map(function(_v) {
       
   115                 return _v / _group.length;
       
   116             }))
       
   117         } else {
       
   118             for (var j = 0; j < _paths.length; j++) {
       
   119                 _paths[j].push(this.height);
       
   120             }
       
   121             this.groups.push(this.tagconf.map(function() {
       
   122                 return 0;
       
   123             }));
       
   124         }
       
   125     }
       
   126     
       
   127     if (this.isStreamGraph) {
       
   128         for (var j = _paths.length - 1; j >= 0; j--) {
       
   129             var _d = _paths[j].reduce(function(_memo, _v, _k) {
       
   130                return _memo + ( _k
       
   131                    ? 'C' + (_k * _width) + ' ' + _paths[j][_k - 1] + ' ' + (_k * _width) + ' ' + _v + ' ' + ((_k + .5) * _width) + ' ' + _v
       
   132                    : 'M0 ' + _v + 'L' + (.5*_width) + ' ' + _v )
       
   133             },'') + 'L' + this.width + ' ' + _paths[j][_paths[j].length - 1] + 'L' + this.width + ' ' + this.height + 'L0 ' + this.height;
       
   134             this.paper.path(_d).attr({
       
   135                 "stroke" : "none",
       
   136                 "fill" : (j ? this.tagconf[j-1].color : this.defaultcolorconf),
       
   137             });
       
   138         }
       
   139     }
       
   140     this.rectangleFocus = this.paper.rect(0,0,_width,this.height)
       
   141         .attr({
       
   142             "stroke" : "none",
       
   143             "fill" : "#ff00ff",
       
   144             "opacity" : 0,
       
   145         })
       
   146     this.rectangleProgress = this.paper.rect(0,0,0,this.height)
       
   147         .attr({
       
   148             "stroke" : "none",
       
   149             "fill" : "#808080",
       
   150             "opacity" : .3,
       
   151         });
       
   152     this.ligneProgress = this.paper.path("M0 0L0 "+this.height).attr({"stroke":"#ff00ff", "line-width" : 2})
       
   153     
       
   154     this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeUpdateHandler));
       
   155     var _this = this;
       
   156     this.selector
       
   157         .click(function(_e) {
       
   158             _this.clickHandler(_e);
       
   159         })
       
   160         .mousemove(function(_e) {
       
   161             _this.updateTooltip(_e);
       
   162         })
       
   163         .mouseout(function() {
       
   164             _this.TooltipWidget.hide();
       
   165             _this.rectangleFocus.attr({
       
   166                 "opacity" : 0,
       
   167             })
       
   168         })
       
   169 }
       
   170 
       
   171 IriSP.StackGraphWidget.prototype.timeUpdateHandler = function() {
       
   172     var _currentTime = this._Popcorn.currentTime(),
       
   173         _x = (1000 * _currentTime / this.duration) * this.width;
       
   174     this.rectangleProgress.attr({
       
   175         "width" : _x,
       
   176     });
       
   177     this.ligneProgress.attr({
       
   178         "path" : "M" + _x + " 0L" + _x + " " + this.height,
       
   179     })
       
   180 }
       
   181 
       
   182 IriSP.StackGraphWidget.prototype.clickHandler = function(event) {
       
   183   /* Ctrl-C Ctrl-V'ed from another widget
       
   184   */
       
   185 
       
   186   var relX = event.pageX - this.selector.offset().left;
       
   187   var newTime = ((relX / this.width) * this.duration/1000).toFixed(2);
       
   188   this._Popcorn.trigger("IriSP.StackGraphWidget.clicked", newTime);
       
   189   this._Popcorn.currentTime(newTime);                                 
       
   190 };
       
   191 
       
   192 IriSP.StackGraphWidget.prototype.updateTooltip = function(event) {
       
   193     var _segment = ~~(this.sliceCount * (event.pageX - this.selector.offset().left)/this.width),
       
   194         _valeurs = this.groups[_segment],
       
   195         _width = this.width / this.sliceCount,
       
   196         _html = '<ul style="list-style: none; margin: 0; padding: 0;">' + this.tagconf.map(function(_tag, _i) {
       
   197             return '<li style="clear: both;"><span style="float: left; width: 10px; height: 10px; margin: 2px; background: '
       
   198                 + _tag.color
       
   199                 + ';"></span>'
       
   200                 + ~~(100 * _valeurs[_i])
       
   201                 + '% de '
       
   202                 + _tag.description
       
   203                 + '</li>';
       
   204         }).join('') + '</ul>';
       
   205     this.TooltipWidget._shown = false; // Vraiment, on ne peut pas ouvrir le widget s'il n'est pas encore ouvert ?
       
   206     this.TooltipWidget.show('','',event.pageX - 105, event.pageY - 160);
       
   207     this.TooltipWidget.selector.find(".tip").html(_html);
       
   208     this.rectangleFocus.attr({
       
   209         "x" : _segment * _width,
       
   210         "opacity" : .4,
       
   211     })
       
   212 }
       
   213