|
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 |