js/playscreen.js
changeset 5 490e4d1b6fee
child 6 14dd1980b0b9
equal deleted inserted replaced
4:26a901771957 5:490e4d1b6fee
       
     1 var topicPoubelle = 13;
       
     2 
       
     3 var adjust = 54;
       
     4 
       
     5 var deltaT = new Date("Wed, 02 May 2012 19:00:00 +0000") / 1000 + adjust;
       
     6 
       
     7 function solrUrl(table, params) {
       
     8     return "http://159.217.144.101:8050/sia-solr/" + table + "/select?" + $.param(params) + "&wt=json&json.wrf=?";
       
     9 }
       
    10 
       
    11 function showData() {
       
    12     
       
    13     var topicHash = document.location.hash || "#topics=5,15";
       
    14     
       
    15     var ordertag = 0;
       
    16 
       
    17     function secsToString(seconds) {
       
    18         var hours = Math.floor(seconds/3600),
       
    19             minutes = Math.floor(seconds/60) % 60,
       
    20             secs = Math.floor(seconds % 60);
       
    21         function pad(n) {
       
    22             var r = n.toString();
       
    23             while (r.length < 2) {
       
    24                 r = "0" + r;
       
    25             }
       
    26             return r;
       
    27         }
       
    28         return (hours ? (hours + ":") : "") + pad(minutes) + ":" + pad(secs);
       
    29     }
       
    30     
       
    31     $(".duration").text(secsToString(data.duration));
       
    32         
       
    33     var nmmso = data.segments.length;
       
    34     
       
    35     data.topics.forEach(function(topic) {
       
    36         topic.score = 0;
       
    37         topic.weights = [];
       
    38         for (var i = 0; i < nmmso; i++) {
       
    39             topic.weights.push(0);
       
    40         }
       
    41     });
       
    42     
       
    43     data.segments.forEach(function(mmso, i) {
       
    44         mmso.topics.forEach(function(t) {
       
    45             data.topics[t.topic].weights[i] = t.weight;
       
    46             data.topics[t.topic].score += t.weight;
       
    47         });
       
    48     });
       
    49     
       
    50     var sortedTopics = data.topics.filter(function(t) {
       
    51         return t.index !== topicPoubelle;
       
    52     }).sort(function(a,b) {
       
    53         return b.score - a.score;
       
    54     });
       
    55     
       
    56     
       
    57     function showTopics(topiclist) {
       
    58         var tbhtml = topiclist.reduce(function(mem, topic) {
       
    59             var wordsToShow = topic.words.slice(0,3),
       
    60                 max = wordsToShow[0].weight,
       
    61                 min = Math.min(wordsToShow[wordsToShow.length - 1].weight, max - .01),
       
    62                 scale = 8 / (max - min);
       
    63             var li = '<li class="shadow-block topic" data-topic-id="'
       
    64                 + topic.index
       
    65                 + '" data-timestamp="999999"><ul class="topic-words">'
       
    66                 + wordsToShow.reduce(function(memwords, word) {
       
    67                     return memwords
       
    68                         + '<li style="font-size: '
       
    69                         + ( 8 + scale * (word.weight - min) )
       
    70                         + 'px;">'
       
    71                         + word.word
       
    72                         + '</li>';
       
    73                 },"")
       
    74                 + '</ul></li>';
       
    75             return mem + li;
       
    76         },'');
       
    77         var tb = $(".topics-block");
       
    78         tb.html(tbhtml);
       
    79         tb.css("top",0);
       
    80         
       
    81         showTopicViz();
       
    82     }
       
    83     
       
    84     var tweetLines = [];
       
    85     
       
    86     function showTopicViz() {
       
    87         var selectedBlocks = $(".topic.selected, .topic.hover"),
       
    88             sbl = selectedBlocks.length,
       
    89             topicBlocks = $(".topic");
       
    90         if (!sbl && topicBlocks.length < sortedTopics.length) {
       
    91             selectedBlocks = topicBlocks;
       
    92             sbl = selectedBlocks.length;
       
    93         }
       
    94         var topicsAndColors = [],
       
    95         	colors = {};
       
    96         selectedBlocks.each(function() {
       
    97             var el = $(this),
       
    98                 topicid = parseInt(el.attr("data-topic-id"));
       
    99             topicsAndColors.push({
       
   100                 "$": el,
       
   101                 timestamp: parseInt(el.attr("data-timestamp")),
       
   102                 hovered: el.hasClass("hover"),
       
   103                 id: topicid,
       
   104                 topic: data.topics[topicid]
       
   105             });
       
   106         });
       
   107         topicsAndColors.sort(function(a,b) {
       
   108            return ( a.timestamp - b.timestamp ) || ( a.id - b.id );
       
   109         });
       
   110         topicBlocks.css("background","");
       
   111         topicsAndColors.forEach(function(topic, i) {
       
   112             topic.color = topic.hovered ? "#ffff00" : colorset[i % colorset.length];
       
   113             colors[topic.id] = topic.color;
       
   114             topic.$.css("background", topic.color);
       
   115         });
       
   116         
       
   117         for (var i = 0; i < nmmso; i++) {
       
   118             var opacity = 0,
       
   119                 rgb = [0,0,0];
       
   120             topicsAndColors.forEach(function(topic) {
       
   121                 var c = Raphael.getRGB(topic.color),
       
   122                     o = topic.topic.weights[i];
       
   123                 rgb[0] += c.r * o;
       
   124                 rgb[1] += c.g * o;
       
   125                 rgb[2] += c.b * o;
       
   126                 opacity += o;
       
   127             });
       
   128             if (opacity) {
       
   129                 color = Raphael.rgb.apply(Raphael, rgb.map(function(c) {
       
   130                     return c/opacity;
       
   131                 }));
       
   132                 var attr = {
       
   133                     fill: color,
       
   134                     opacity: .5 + .5 * opacity
       
   135                 };
       
   136                 segmentrects[i].show();
       
   137                 segmentrects[i].attr(attr);
       
   138                 if (i >= localMmsoDelta && i < localMmsoDelta + localMmsos.length) {
       
   139                 	localMmsos[i - localMmsoDelta].show();
       
   140                 	localMmsos[i - localMmsoDelta].attr(attr);
       
   141                 }
       
   142             } else {
       
   143                 segmentrects[i].hide();
       
   144                 if (i >= localMmsoDelta && i < localMmsoDelta + localMmsos.length) {
       
   145                 	localMmsos[i - localMmsoDelta].hide();
       
   146                 }
       
   147             }
       
   148         }
       
   149         
       
   150         tweetLines.forEach(function(tl) { tl.remove(); });
       
   151         tweetLines = [];
       
   152         
       
   153         var deltaY = $(".play-dataviz").offset().top;
       
   154         
       
   155         $(".play-localtweets .tweet").each(function() {
       
   156         	var el = $(this),
       
   157         		liY = + el.offset().top + el.outerHeight() / 2 - deltaY,
       
   158         		tY = localyscale * (+el.attr("data-timestamp") - localpos + localduration / 2),
       
   159         		p = "M" + localL + "," + tY + "L" + localR + "," + tY + "L320," + liY,
       
   160         		path = paper.path(p);
       
   161     		$(this).css("background",colors[el.attr("data-topic-id")] || "");
       
   162     		path.attr({
       
   163     			stroke: "#ccc"
       
   164     		});
       
   165     		tweetLines.push(path);
       
   166         });
       
   167         throttledGetTweets();
       
   168         
       
   169     }
       
   170     
       
   171     var jqsvg = $(".play-svg"),
       
   172         paper = new Raphael(jqsvg[0]),
       
   173         totalR = jqsvg.width(),
       
   174         ph = jqsvg.height(),
       
   175         globW = 85,
       
   176         globL = 40,
       
   177         localL = 155,
       
   178         localW = 85,
       
   179         localR = (localL + localW),
       
   180         localTimeR = (localL + localW) + globL,
       
   181         globR = (globW + globL),
       
   182         yscale = ph / data.duration,
       
   183         mx = Math.max.apply(Math, data.minutes.map(function(s) { return s.count})),
       
   184         xscale = globW/mx;
       
   185     
       
   186     var segmentrects = data.segments.map(function(mmso) {
       
   187         var rect = paper.rect(globL, yscale * mmso.start, globW, yscale * mmso.duration);
       
   188         rect.attr({stroke: "none"});
       
   189         return rect;
       
   190     });
       
   191     
       
   192     var d = "M" + data.minutes.map(function(s) {
       
   193             var x = globL + xscale * s.count;
       
   194             return x
       
   195                 + ","
       
   196                 + yscale * (s.from + 20)
       
   197                 + "L"
       
   198                 + x
       
   199                 + ","
       
   200                 + yscale * (s.from + 40);
       
   201         }).join("L");
       
   202         
       
   203     paper.path(d).attr({
       
   204         "stroke-width": 4,
       
   205         "stroke": "#000000",
       
   206         opacity: .5
       
   207     });
       
   208     paper.path(d).attr({
       
   209         "stroke-width": 1,
       
   210         "stroke": "#ffffff"
       
   211     });
       
   212     
       
   213     for (var i=0; i < data.duration; i += 1800) {
       
   214         var y = yscale * i;
       
   215         paper.path("M0" + "," + y + "l" + globR + ",0").attr({stroke: "#666"});
       
   216         paper.text(0, y + 6, secsToString(i)).attr({
       
   217         	"text-anchor": "start",
       
   218             "fill": "#ffffff"
       
   219         });
       
   220     }
       
   221     paper.text(0, ph-8, secsToString(data.duration)).attr({
       
   222         "text-anchor": "start",
       
   223         "fill": "#ffffff"
       
   224     });
       
   225     paper.path("M0" + globR + ",0L" + localTimeR + ",0" ).attr({stroke: "#666"});
       
   226     paper.path("M0," + (ph-1) + "l" + localTimeR + ",0" ).attr({stroke: "#666"});
       
   227     
       
   228     paper.path("M" + globR + ",0l0," + ph).attr({stroke: "#666"});
       
   229     paper.path("M" + localL + ",0l0," + ph).attr({stroke: "#666"});
       
   230     
       
   231     var entonnoir = paper.path("").attr("fill","#333"),
       
   232     	localStartText = paper.text(localTimeR,6,"").attr({
       
   233     		"text-anchor": "end",
       
   234     		"fill": "#ffffff"
       
   235     	}),
       
   236     	localEndText = paper.text(localTimeR,ph - 8, "").attr({
       
   237     		"text-anchor": "end",
       
   238     		"fill": "#ffffff"
       
   239     	}),
       
   240     	localTimes = [],
       
   241     	localMmsos = [],
       
   242     	localMmsoDelta,
       
   243     	mmsoAlt = [],
       
   244     	lowerFiveSecs,
       
   245     	higherFiveSecs,
       
   246     	localyscale;
       
   247 	
       
   248 	entonnoir.toBack();
       
   249     
       
   250     function showLocal() {
       
   251 		localyscale = ph / localduration;
       
   252     	var localstart = localpos - localduration/2;
       
   253     		localend = localpos + localduration/2;
       
   254     		globtop = yscale * localstart,
       
   255     		globbottom = yscale * localend,
       
   256     		betweenx = (globR + localL) / 2,
       
   257     		betweenyt = (globtop) / 2,
       
   258     		betweenyb = (globbottom + ph) / 2,
       
   259     		curve = (localL - globR) / 2,
       
   260     		entonnoird = "M0," + globtop + "l" + globR + ",0Q" + betweenx + "," + globtop + "," + betweenx + ","
       
   261     			+ Math.max(globtop - curve, betweenyt) + "L" + betweenx + "," + Math.min(curve, betweenyt) + "Q"
       
   262     			+ betweenx + ",0," + localL + ",0"
       
   263     			+ "L" + localR + ",0L" + localR + "," + ph + "L" + localL + "," + ph + "Q" + betweenx + "," + ph + ","
       
   264     			+ betweenx + "," + Math.max(ph - curve, betweenyb) +"L" + betweenx + "," + Math.min(globbottom + curve, betweenyb)
       
   265     			+ "Q" + betweenx + "," + globbottom + "," + globR + "," + globbottom + "L0," + globbottom;
       
   266 			
       
   267 		entonnoir.attr("path",entonnoird);
       
   268 		localTimes.forEach(function(t) {
       
   269 			t.text.remove();
       
   270 			t.line.remove();
       
   271 		});
       
   272 		localMmsos.forEach(function(t) {
       
   273 			t.remove();
       
   274 		});
       
   275 		mmsoAlt.forEach(function(t) {
       
   276 			t.remove();
       
   277 		});
       
   278 		var filteredSegments = data.segments.filter(function(s) {
       
   279 			return s.start < localend && s.end > localstart;
       
   280 		});
       
   281 		localMmsoDelta = parseInt(filteredSegments[0].id.split("_")[1]);
       
   282 		localMmsos = filteredSegments.map(function(s) {
       
   283 			var y = localyscale * (s.start - localstart),
       
   284 				h = localyscale * s.duration;
       
   285 	        var rect = paper.rect( localL, y, localW, h );
       
   286 	        rect.attr({stroke: "none", title: s.id});
       
   287 	        if (parseInt(s.id.replace("MMSO_","")) % 2) {
       
   288 	        	var altrect = paper.rect( localR, y, (totalR - localR), h);
       
   289 	        	altrect.attr({stroke: "none", fill: "#222"});
       
   290 	        	mmsoAlt.push(altrect);
       
   291 	        }
       
   292 	        return rect;
       
   293 		});
       
   294 		localStartText.attr("text", secsToString(localstart)).toFront();
       
   295 		localEndText.attr("text", secsToString(localend)).toFront();
       
   296 		for ( var i = (1 + Math.floor(localstart / 120)) * 120; i < localend; i += 120 ) {
       
   297 			var y = localyscale*(i - localstart)
       
   298 			localTimes.push({
       
   299 				text: paper.text(localTimeR,6+y,secsToString(i)).attr({
       
   300 		    		"text-anchor": "end",
       
   301 		    		"fill": "#ffffff"
       
   302 		    	}),
       
   303 		    	line: paper.path("M0" + localL + "," + y + "L" + localTimeR + "," + y).attr({stroke: "#666"})
       
   304 			});
       
   305 		}
       
   306 		if (lowerFiveSecs) {
       
   307 			lowerFiveSecs.remove();
       
   308 		}
       
   309 		if (higherFiveSecs) {
       
   310 			higherFiveSecs.remove();
       
   311 		}
       
   312 		var filteredFiveSecs = data.fiveseconds.slice(Math.floor(localstart / 5), Math.ceil(localend / 5));
       
   313         var counts = filteredFiveSecs.map(function(s) { return s.count}),
       
   314         	lmx = Math.max.apply(Math, counts),
       
   315         	lmi = Math.min.apply(Math, counts.concat([lmx - 1]))
       
   316         	lxscale = localW/(lmx-lmi);
       
   317        	
       
   318 	    var d = "M" + filteredFiveSecs.map(function(s) {
       
   319 	            var x = localL + lxscale * (s.count - lmi);
       
   320 	            return x
       
   321 	                + ","
       
   322 	                + localyscale * (s.from + 1 - localstart)
       
   323 	                + "L"
       
   324 	                + x
       
   325 	                + ","
       
   326 	                + localyscale * (s.from + 4 - localstart);
       
   327 	        }).join("L");
       
   328 	        
       
   329 	    lowerFiveSecs = paper.path(d).attr({
       
   330 	        "stroke-width": 4,
       
   331 	        "stroke": "#000000",
       
   332 	        opacity: .5
       
   333 	    });
       
   334 	    higherFiveSecs = paper.path(d).attr({
       
   335 	        "stroke-width": 1,
       
   336 	        "stroke": "#ffffff"
       
   337 	    });
       
   338 		showTopicViz();
       
   339     }
       
   340     
       
   341     
       
   342     var lastPos, lastDuration, lastTopics;
       
   343     
       
   344     var tweetTemplate = _.template('<li class="tweet" data-timestamp="<%= _timestamp %>" data-topic-id="<%= _topic %>"><img src="<%- profile_image_url %>" /><p>@<%- from_user_name %>: <%- text %></p></li>'),
       
   345     	callnum = 0;
       
   346     
       
   347     function getTweets() {
       
   348     	var topicIds = Array.prototype.join.call($(".topic.selected").map(function(){return $(this).attr("data-topic-id")}));
       
   349     	if (localduration === lastDuration && lastTopics === topicIds && Math.abs(localpos - lastPos) < (localduration / 10)) {
       
   350     		console.log("We already have these tweets, delta =", localpos - lastPos );
       
   351     		return;
       
   352     	}
       
   353     	if (!topicIds) {
       
   354     		console.log("No topics selected");
       
   355     		return;
       
   356     	}
       
   357     	var localcall = ++callnum;
       
   358     	console.log("getTweets was called",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date()));
       
   359     	var tweetids = {},
       
   360     		rqtodo = 0,
       
   361     		rqdone = 0,
       
   362     		topics = topicIds.split(",");
       
   363     	
       
   364     	function getMmsoTopicTweets(mmsoid, topic, ntweets) {
       
   365     		rqtodo++;
       
   366 			TopicsBean.bestSocialInteractionsIdsMatching(mmsoid, topic, 0, ntweets, {
       
   367 				callback: function(tw) {
       
   368 					for (var k = 0; k < tw.length; k++) {
       
   369 						tweetids[tw[k]] = topic;
       
   370 					}
       
   371 					rqdone++;
       
   372 					if (rqdone === rqtodo) {
       
   373 						loadTweets();
       
   374 					}
       
   375 				}
       
   376 			});
       
   377     	}
       
   378     	
       
   379     	function loadTweets() {
       
   380     		console.log("Tweet IDs retrieved",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date()));
       
   381     		var u = _.keys(tweetids);
       
   382 			$.getJSON(
       
   383 				solrUrl(
       
   384 					"twitter",
       
   385 					{
       
   386 						q:"id:(" + u.join(" OR ") + ")",
       
   387 						rows: u.length
       
   388 					}
       
   389 				),
       
   390 				function(t) {
       
   391     				console.log("Full tweets retrieved",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date()));
       
   392 					var tweets = t.response.docs;
       
   393 					var s = 600 / (1+tweets.length);
       
   394 					tweets.forEach(function(tweet, i) {
       
   395 						tweet._date = new Date(tweet.created_at);
       
   396 						tweet._timestamp = tweet._date.valueOf() / 1000 - deltaT;
       
   397 						tweet._topic = tweetids[tweet.id_str]
       
   398 					});
       
   399 					tweets.sort(function(a,b) {
       
   400 						return a._date - b._date;
       
   401 					});
       
   402 					var html = tweets.reduce(function(mem, tweet) {
       
   403 						return mem + tweetTemplate(tweet);
       
   404 					},'');
       
   405 					$(".play-localtweets").html(html);
       
   406 					var h = 0;
       
   407 					$(".play-localtweets .tweet").each(function() {
       
   408 						h += $(this).outerHeight();
       
   409 					});
       
   410 					$(".play-localtweets .tweet").css("margin-top",Math.max(0,($(".play-bottom").height() - h)/(tweets.length+1)));
       
   411 					showTopicViz();
       
   412 				}
       
   413 			);
       
   414 			$(".play-localtweets").html("");
       
   415 			showTopicViz();
       
   416     	}
       
   417     	
       
   418     	function getMmsoTweets(nmmso) {
       
   419     		var mmso = data.segments[nmmso],
       
   420     			mmsopixels = localyscale * (Math.min(localpos + localduration / 2, mmso.end) - Math.max(localpos - localduration / 2, mmso.start));
       
   421     		var ntweets = Math.floor(( 50 + mmsopixels ) / 80),
       
   422     			mmsotopics = [];
       
   423 			if (!ntweets) {
       
   424 				return;
       
   425 			}
       
   426 			for (var j = 0; j < topics.length; j++) {
       
   427 				var weight = data.topics[topics[j]].weights[nmmso];
       
   428 				if (weight > .05) {
       
   429 					mmsotopics.push({topic:parseInt(topics[j]),weight:weight,ntweets:0});
       
   430 				}
       
   431 			}
       
   432 			mmsotopics.sort(function(a,b){return b.weight - a.weight});
       
   433 			if (mmsotopics.length) {
       
   434 				for (var j = 0; j < ntweets; j++) {
       
   435 					mmsotopics[j % mmsotopics.length].ntweets++;
       
   436 				}
       
   437 				mmsotopics = mmsotopics.filter(function(t) { return !!t.ntweets });
       
   438 				for (var j = 0; j < mmsotopics.length; j++) {
       
   439 					getMmsoTopicTweets(mmso.id, mmsotopics[j].topic, mmsotopics[j].ntweets);
       
   440 				}
       
   441 			} else {
       
   442 				var t = [], m = {};
       
   443 				while (t.length < ntweets) {
       
   444 					t = t.concat(topics);
       
   445 				}
       
   446 				for (var j = 0; j < ntweets; j++) {
       
   447 					m[t[j]] = 1 + (m[t[j]]||0);
       
   448 				}
       
   449 				_(m).each(function(v,k) {
       
   450 					getMmsoTopicTweets(mmso.id, k, v);
       
   451 				});
       
   452 			}
       
   453     	}
       
   454     	
       
   455     	dwr.engine.beginBatch();
       
   456     	for (var i = 0; i < localMmsos.length; i++) {
       
   457     		getMmsoTweets(localMmsoDelta + i);
       
   458     	}
       
   459     	dwr.engine.endBatch();
       
   460     	lastPos = localpos;
       
   461     	lastDuration = localduration;
       
   462     	lastTopics = topicIds;
       
   463     }
       
   464     
       
   465     var throttledGetTweets = _.throttle(_.debounce(getTweets, 500), 10000),
       
   466     	throttledShowLocal = _.throttle(showLocal, 100);
       
   467     
       
   468     showTopics(sortedTopics);
       
   469     (topicHash.match(/\d+/g) || []).forEach(function(id) {
       
   470     	$(".topic[data-topic-id=" + id + "]").addClass("selected").attr("data-timestamp",++ordertag);
       
   471     });
       
   472     
       
   473     var localpos = 7100,
       
   474     	localduration = 600;
       
   475     	
       
   476     showLocal();
       
   477     
       
   478     $(".topics-block").on("mouseenter", ".topic", function() {
       
   479         var el = $(this);
       
   480         el.addClass("hover");
       
   481         showTopicViz();
       
   482     }).on("mouseleave", ".topic", function() {
       
   483         $(this).removeClass("hover");
       
   484         showTopicViz();
       
   485     }).on("click", ".topic", function() {
       
   486         var el = $(this);
       
   487         $(this).toggleClass("selected");
       
   488         el.attr("data-timestamp", el.hasClass("selected") ? ++ordertag : 999999);
       
   489         showTopicViz();
       
   490     });
       
   491     
       
   492     var mouseIsDown, isDragging, startY, startT, startPos, scrollGlobal, speedscale, slowiterations;
       
   493     
       
   494     function inertia() {
       
   495     	startPos = localpos;
       
   496     	window.setTimeout(function() {
       
   497     		speedscale = .75 * speedscale;
       
   498     		localstart += 100*speedscale;
       
   499     		throttledShowLocal();
       
   500     		if (slowiterations < 5) {
       
   501     			inertia();
       
   502     		}
       
   503     		slowiterations++;
       
   504     	}, 100);
       
   505     }
       
   506     
       
   507     $("body").mouseup(function() { mouseIsDown = false; });
       
   508     
       
   509     $(".play-dataviz").mousedown(function(e) {
       
   510     	var l = $(this).offset().left,
       
   511     		scrollLimit = l + 280;
       
   512 		if (e.pageX < scrollLimit) {
       
   513 			mouseIsDown = true;
       
   514 	    	startY = e.pageY;
       
   515 	    	startT = new Date();
       
   516 	    	startPos = localpos;
       
   517 	    	scrollGlobal = e.pageX < (l + 140);
       
   518 	    	e.preventDefault();
       
   519 		}
       
   520     }).mousemove(function(e) {
       
   521     	if (mouseIsDown) {
       
   522     		if (isDragging) {
       
   523     			var limit = $(this).offset().left + 140,
       
   524     				deltaY = e.pageY - startY,
       
   525     				delta = Math.floor(deltaY / (scrollGlobal ? yscale : - localyscale));
       
   526 				localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, startPos + delta));
       
   527 				throttledShowLocal();
       
   528     		} else {
       
   529     			isDragging = true;
       
   530     		}
       
   531     	}
       
   532     }).mouseup(function(e) {
       
   533     	if (scrollGlobal && !isDragging) {
       
   534     		
       
   535     		var posY = e.pageY - $(this).offset().top;
       
   536     		localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, Math.floor(posY / yscale)));
       
   537 			throttledShowLocal();
       
   538     	}
       
   539 /*    	if (isDragging) {
       
   540 			var limit = $(this).offset().left + 140,
       
   541 				deltaY = e.pageY - startY,
       
   542 				deltaT = new Date() - startT,
       
   543 				delta = Math.floor(deltaY / (scrollGlobal ? yscale : - localyscale));
       
   544 			speedscale = delta / deltaT;
       
   545 			slowiterations = 0;
       
   546 			inertia();
       
   547     } */
       
   548     });
       
   549     
       
   550     var totalScroll = 0, zoomlevels = [ 1800, 900, 600, 300, 120, 60 ], currentlevel = 2;
       
   551     
       
   552     $(".play-dataviz").mousewheel(function(_event, _scrolldelta) {
       
   553     	totalScroll += _scrolldelta;
       
   554 	    if (Math.abs(totalScroll) >= 1) {
       
   555 	    	var d = (totalScroll > 0 ? 1 : -1),
       
   556 	    		newlevel = Math.max(0, Math.min(zoomlevels.length - 1, currentlevel + d));
       
   557     		if (newlevel !== currentlevel) {
       
   558     			currentlevel = newlevel;
       
   559     			localduration = zoomlevels[currentlevel];
       
   560     			localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, localpos));
       
   561     			throttledShowLocal();
       
   562     		}
       
   563 	        totalScroll = 0;
       
   564 	    }
       
   565     })
       
   566     
       
   567 }
       
   568 
       
   569 var data = { duration: 10200, topics: [] },
       
   570     colorset = ["#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#A65628", "#F781BF"];
       
   571 
       
   572 $(function() {
       
   573 	
       
   574 	dwr.engine.setErrorHandler(function(a, b) { console.error("DWR", b); });
       
   575     
       
   576     $(".topics-block").draggable({axis:"x"});
       
   577     
       
   578     var loadedSteps = 0,
       
   579         stepsToFullyLoaded = 0;
       
   580     
       
   581     function checkIfLoaded() {
       
   582         loadedSteps++;
       
   583         if (loadedSteps >= stepsToFullyLoaded) {
       
   584             setTimeout(showData,0);
       
   585         }
       
   586     }
       
   587     
       
   588     function loadJson(url, propname, callback) {
       
   589         stepsToFullyLoaded++;
       
   590         $.getJSON(url, function(d) {
       
   591             if (callback) {
       
   592                 var res = callback(d);
       
   593             } else {
       
   594                 var res = d;
       
   595             }
       
   596             if (propname) {
       
   597                 data[propname] = res;
       
   598             }
       
   599             checkIfLoaded();
       
   600         });
       
   601     }
       
   602     
       
   603     function loadFromTopicsBean(method, propname, args, callback) {
       
   604         stepsToFullyLoaded++;
       
   605         var arg = args || [],
       
   606             cb = function(d) {
       
   607                 if (callback) {
       
   608                     var res = callback(d);
       
   609                 } else {
       
   610                     var res = d;
       
   611                 }
       
   612                 if (propname) {
       
   613                     data[propname] = res;
       
   614                 }
       
   615                 checkIfLoaded();
       
   616             }
       
   617         arg.push({callback: cb});
       
   618         TopicsBean[method].apply(TopicsBean,arg);
       
   619     }
       
   620     
       
   621     loadJson("data/minutes.json", "minutes");
       
   622     loadJson("data/5secs.json", "fiveseconds");
       
   623     
       
   624     loadJson(
       
   625         solrUrl("MMSO", {q: "*:*", fl: "topic*,MMSO_id,multimediaSegment", rows: 250 }),
       
   626         "segments",
       
   627         function(d) {
       
   628             return d.response.docs.map(function(mmso) {
       
   629                 var tc = mmso.multimediaSegment.match(/\d+/g),
       
   630                     start = parseInt(tc[0]),
       
   631                     end = parseInt(tc[1]),
       
   632                     topics = [];
       
   633                 for (var k in mmso) {
       
   634                     if (k.substr(0,5) === "topic" && mmso[k] > .01) {
       
   635                         topics.push({
       
   636                             topic: parseInt(k.substr(5)),
       
   637                             weight: mmso[k]
       
   638                         })
       
   639                     }
       
   640                 }
       
   641                 topics.sort(function(a,b) {
       
   642                     return b.weight - a.weight;
       
   643                 });
       
   644 /*                topics = topics.filter(function(t) {
       
   645                     return t.topic !== topicPoubelle
       
   646                 }).slice(0,1);
       
   647                 topics[0].weight = 1; */
       
   648                 return {
       
   649                     id: mmso.MMSO_id,
       
   650                     start: start,
       
   651                     end: end,
       
   652                     duration: end - start,
       
   653                     topics: topics
       
   654                 }
       
   655             }).sort(function(a,b) {
       
   656                 return a.start - b.start;
       
   657             });
       
   658         })
       
   659     
       
   660     dwr.engine.setTimeout(60000);
       
   661     TopicsBean._path = "http://159.217.144.101:8050/sia-solr/dwr";
       
   662     
       
   663     loadFromTopicsBean("getTopicsNumber",false,false,function(topic_count) {
       
   664         for (var i = 0; i < topic_count; i++) {
       
   665             data.topics.push(null);
       
   666         }
       
   667         dwr.engine.beginBatch();
       
   668         data.topics.forEach(function(v, k) {
       
   669             loadFromTopicsBean("getTopicDistribution",false,[k, 50, false],function(topic) {
       
   670                 var words = topic.match(/[^=,{]+=0.\d{0,8}/g);
       
   671                 data.topics[k] = {
       
   672                     index: k,
       
   673                     words: words.map(function(w) {
       
   674                         var parts = w.split("=");
       
   675                         return {
       
   676                             word: parts[0].trim(),
       
   677                             weight: parseFloat(parts[1])
       
   678                         }
       
   679                     })
       
   680                 }
       
   681             });
       
   682             
       
   683         });
       
   684         dwr.engine.endBatch();
       
   685         
       
   686     });
       
   687     
       
   688     
       
   689 });