js/playscreen.js
changeset 6 14dd1980b0b9
parent 5 490e4d1b6fee
child 7 a2d5b669f663
equal deleted inserted replaced
5:490e4d1b6fee 6:14dd1980b0b9
   150         tweetLines.forEach(function(tl) { tl.remove(); });
   150         tweetLines.forEach(function(tl) { tl.remove(); });
   151         tweetLines = [];
   151         tweetLines = [];
   152         
   152         
   153         var deltaY = $(".play-dataviz").offset().top;
   153         var deltaY = $(".play-dataviz").offset().top;
   154         
   154         
   155         $(".play-localtweets .tweet").each(function() {
   155         $(".play-localtweets .tweet:visible").each(function() {
   156         	var el = $(this),
   156         	var el = $(this),
   157         		liY = + el.offset().top + el.outerHeight() / 2 - deltaY,
   157         		liY = + el.offset().top + el.outerHeight() / 2 - deltaY,
   158         		tY = localyscale * (+el.attr("data-timestamp") - localpos + localduration / 2),
   158         		tY = localyscale * (+el.attr("data-timestamp") - localpos + localduration / 2),
   159         		p = "M" + localL + "," + tY + "L" + localR + "," + tY + "L320," + liY,
   159         		p = "M" + localL + "," + tY + "L" + localR + "," + tY + "L400," + liY,
   160         		path = paper.path(p);
   160         		path = paper.path(p);
   161     		$(this).css("background",colors[el.attr("data-topic-id")] || "");
   161     		$(this).css("background",colors[el.attr("data-topic-id")] || "");
   162     		path.attr({
   162     		path.attr({
   163     			stroke: "#ccc"
   163     			stroke: "#ccc"
   164     		});
   164     		});
   165     		tweetLines.push(path);
   165     		tweetLines.push(path);
   166         });
   166         });
   167         throttledGetTweets();
       
   168         
   167         
   169     }
   168     }
   170     
   169     
   171     var jqsvg = $(".play-svg"),
   170     var jqsvg = $(".play-svg"),
   172         paper = new Raphael(jqsvg[0]),
   171         paper = new Raphael(jqsvg[0]),
   283 			var y = localyscale * (s.start - localstart),
   282 			var y = localyscale * (s.start - localstart),
   284 				h = localyscale * s.duration;
   283 				h = localyscale * s.duration;
   285 	        var rect = paper.rect( localL, y, localW, h );
   284 	        var rect = paper.rect( localL, y, localW, h );
   286 	        rect.attr({stroke: "none", title: s.id});
   285 	        rect.attr({stroke: "none", title: s.id});
   287 	        if (parseInt(s.id.replace("MMSO_","")) % 2) {
   286 	        if (parseInt(s.id.replace("MMSO_","")) % 2) {
   288 	        	var altrect = paper.rect( localR, y, (totalR - localR), h);
   287 	        	var altrect = paper.rect( localR, y, 60, h);
   289 	        	altrect.attr({stroke: "none", fill: "#222"});
   288 	        	altrect.attr({stroke: "none", fill: "#222"});
   290 	        	mmsoAlt.push(altrect);
   289 	        	mmsoAlt.push(altrect);
   291 	        }
   290 	        }
   292 	        return rect;
   291 	        return rect;
   293 		});
   292 		});
   333 	    });
   332 	    });
   334 	    higherFiveSecs = paper.path(d).attr({
   333 	    higherFiveSecs = paper.path(d).attr({
   335 	        "stroke-width": 1,
   334 	        "stroke-width": 1,
   336 	        "stroke": "#ffffff"
   335 	        "stroke": "#ffffff"
   337 	    });
   336 	    });
       
   337 	    
       
   338 	    var imghtm = '', imgrate = localduration / 12, imgstart = imgrate * Math.floor(localstart / imgrate), imgend = imgrate * Math.ceil(localend / imgrate);
       
   339 	    for (var i = imgstart; i <= imgend; i+= imgrate) {
       
   340 	    	var imgsrc = i + '.png';
       
   341 	    	while (imgsrc.length < 9) {
       
   342 	    		imgsrc = '0' + imgsrc;
       
   343 	    	}
       
   344 	    	var imgy = Math.floor( localyscale * (i - localstart) - 22.5 )
       
   345 	    	imghtm += '<img src="thumbnails/' + imgsrc + '" style="top: ' + imgy +'px;" />';
       
   346 	    }
       
   347 	    $(".play-images").html(imghtm);
       
   348 	    
       
   349 	    $(".play-localtweets .tweet").each(function() {
       
   350 	    	var el = $(this),
       
   351 	    		t = parseInt(el.attr("data-timestamp"));
       
   352     		if (t > localstart && t < localend) {
       
   353     			el.show();
       
   354     		} else {
       
   355     			el.hide();
       
   356     		}
       
   357 	    });
       
   358 	    
       
   359 		throttledGetTweets();
       
   360 	    
   338 		showTopicViz();
   361 		showTopicViz();
   339     }
   362     }
   340     
   363     
   341     
   364     
   342     var lastPos, lastDuration, lastTopics;
   365     var lastPos, lastDuration, lastTopics;
   343     
   366     
   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>'),
   367     var tweetTemplate = _.template('<li class="tweet" data-timestamp="<%= timestamp %>" data-topic-id="<%= topic.topic %>"><img src="<%- data.profile_image_url %>" /><p>@<%- data.from_user_name %>: <%- data.text %></p></li>'),
   345     	callnum = 0;
   368     	callnum = 0,
   346     
   369     	tweetstructure = {},
   347     function getTweets() {
   370     	requestedtweets = {},
   348     	var topicIds = Array.prototype.join.call($(".topic.selected").map(function(){return $(this).attr("data-topic-id")}));
   371     	_NTWEETS = 10;
   349     	if (localduration === lastDuration && lastTopics === topicIds && Math.abs(localpos - lastPos) < (localduration / 10)) {
   372     
   350     		console.log("We already have these tweets, delta =", localpos - lastPos );
   373     function showTweets() {
   351     		return;
   374     	    	
       
   375     	var toshow = [];
       
   376     	var topics = Array.prototype.join.call($(".topic.selected").map(function(){return $(this).attr("data-topic-id")})).split(",");
       
   377     	
       
   378     	for (var i = 0; i < localMmsos.length; i++) {
       
   379     		var mmso = data.segments[localMmsoDelta + i];
       
   380     		var mmsostruct = tweetstructure[mmso.id];
       
   381     		if (mmsostruct) {
       
   382 	    		for (var j = 0; j < topics.length; j++) {
       
   383 	    			var topicid = topics[j];
       
   384 					if (mmsostruct[topicid]) {
       
   385 						var tweetids = mmsostruct[topicid].tweetids;
       
   386 						for (var k = 0; k < tweetids.length; k++) {
       
   387 							toshow.push(tweetids[k]);
       
   388 						}
       
   389 					}
       
   390 	    		}
       
   391     		}
   352     	}
   392     	}
   353     	if (!topicIds) {
   393     	toshow = _(toshow).uniq();
   354     		console.log("No topics selected");
   394     	    	
   355     		return;
   395     	var tweetstoshow = toshow.map(function(tid) {
       
   396     		return requestedtweets[tid];
       
   397     	}).filter(function(tw) {
       
   398     		return ((tw.status == 2) && (tw.timestamp > (localpos - localduration / 2)) && (tw.timestamp < (localpos + localduration / 2)));
       
   399 		});
       
   400 		
       
   401 		tweetstoshow.forEach(function(tw) {
       
   402 			tw.topic = tw.topics.filter(function(t) {
       
   403 				return topics.indexOf(t.topic) !== -1;
       
   404 			}).sort(function(a,b) {
       
   405 				return b.weight - a.weight
       
   406 			})[0];
       
   407 		});
       
   408 				
       
   409 		tweetstoshow.sort(function(a, b) {
       
   410 			return b.topic.weight - a.topic.weight; 
       
   411 		});
       
   412 		
       
   413 		tweetstoshow = tweetstoshow.slice(0,10);
       
   414 		
       
   415 		tweetstoshow.sort(function(a, b) {
       
   416 			return a.timestamp - b.timestamp;
       
   417 		});
       
   418 		
       
   419 		console.log(tweetstoshow);
       
   420 		
       
   421 		var html = tweetstoshow.map(tweetTemplate).join("");
       
   422 		
       
   423 		$(".play-localtweets").html(html);
       
   424 		var h = 0;
       
   425 		$(".play-localtweets .tweet").each(function() {
       
   426 			h += $(this).outerHeight();
       
   427 		});
       
   428 		$(".play-localtweets .tweet").css("margin-top",Math.max(0,($(".play-bottom").height() - h)/(tweetstoshow.length+1)));
       
   429 		showTopicViz();
       
   430     	
       
   431     }
       
   432     
       
   433     function getMmsoTweetIds(mmstruct) {
       
   434     	    	
       
   435     	TopicsBean.bestSocialInteractionsIdsMatching(mmstruct.mmso, mmstruct.topic, 0, _NTWEETS, {
       
   436 			callback: function(tw) {
       
   437 				mmstruct.status = 2;
       
   438 				mmstruct.tweetids = tw;
       
   439 				for (var k = 0; k < tw.length; k++) {
       
   440 					var tweetid = tw[k],
       
   441 						relevance = mmstruct.weight * (_NTWEETS - k) / _NTWEETS;
       
   442 					if (!requestedtweets[tweetid]) {
       
   443 						requestedtweets[tweetid] = {
       
   444 							id: tweetid,
       
   445 							status: 0,
       
   446 							topics: []
       
   447 						}
       
   448 					}
       
   449 					requestedtweets[tweetid].topics.push({
       
   450 						topic: mmstruct.topic,
       
   451 						weight: relevance
       
   452 					});
       
   453 				}
       
   454 				debouncedGetTweetData();
       
   455 			},
       
   456 			errorHandler: function(err) {
       
   457 				mmstruct.status = 0;
       
   458 				console.log(err);
       
   459 				throttledGetTweetIds();
       
   460 			}
       
   461 		});
       
   462     }
       
   463     
       
   464     var _MAX_BATCH = 20;
       
   465     
       
   466     function getTweetIds() {
       
   467     	
       
   468     	console.log("getTweetIds");
       
   469     	
       
   470     	var toload = [];
       
   471     	
       
   472     	_(tweetstructure).each(function(v) {
       
   473     		_(v).each(function(w) {
       
   474     			if (!w.status) {
       
   475     				w.status = 1;
       
   476     				toload.push(w);
       
   477     			}
       
   478     		});
       
   479     	});
       
   480     	
       
   481     	console.log("Loading tweet ids");
       
   482     	
       
   483     	if (toload.length) {
       
   484     		
       
   485     		if (toload.length > _MAX_BATCH) {
       
   486     			toload = _(toload).shuffle().slice(0,_MAX_BATCH);
       
   487     			window.setInterval(throttledGetTweetIds,0);
       
   488     		}
       
   489     		
       
   490     		dwr.engine.beginBatch();
       
   491     		toload.forEach(getMmsoTweetIds);
       
   492     		dwr.engine.endBatch();
   356     	}
   493     	}
   357     	var localcall = ++callnum;
   494     }
   358     	console.log("getTweets was called",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date()));
   495     
   359     	var tweetids = {},
   496     function getTweetData() {
   360     		rqtodo = 0,
   497     	
   361     		rqdone = 0,
   498     	console.log("getTweetData");
   362     		topics = topicIds.split(",");
   499     	
   363     	
   500     	var toload = [];
   364     	function getMmsoTopicTweets(mmsoid, topic, ntweets) {
   501     	
   365     		rqtodo++;
   502     	_(requestedtweets).each(function(v) {
   366 			TopicsBean.bestSocialInteractionsIdsMatching(mmsoid, topic, 0, ntweets, {
   503 			if (!v.status) {
   367 				callback: function(tw) {
   504 				toload.push(v.id);
   368 					for (var k = 0; k < tw.length; k++) {
   505 			}
   369 						tweetids[tw[k]] = topic;
   506 		});
   370 					}
   507     	
   371 					rqdone++;
   508     	console.log("Loading tweet data");
   372 					if (rqdone === rqtodo) {
   509 		
   373 						loadTweets();
   510 		$.getJSON(
   374 					}
   511 			solrUrl(
       
   512 				"twitter",
       
   513 				{
       
   514 					q:"id:(" + toload.join(" OR ") + ")",
       
   515 					fl: "id_str,created_at,from_user_name,text,profile_image_url",
       
   516 					rows: toload.length
   375 				}
   517 				}
   376 			});
   518 			),
       
   519 			function(t) {
       
   520 				var tweets = t.response.docs;
       
   521 				tweets.forEach(function(tweet) {
       
   522 					var timestamp = new Date(tweet.created_at).valueOf() / 1000 - deltaT;
       
   523 					requestedtweets[tweet.id_str].data = tweet;
       
   524 					requestedtweets[tweet.id_str].status = 2;
       
   525 					requestedtweets[tweet.id_str].timestamp = timestamp;
       
   526 				});
       
   527 				throttledShowTweets();
       
   528 			}
       
   529 		);
       
   530 		
       
   531     }
       
   532     
       
   533     debouncedGetTweetData = _(getTweetData).debounce(125);
       
   534     
       
   535     throttledGetTweetIds = _(getTweetIds).throttle(10000);
       
   536     
       
   537     throttledShowTweets = _(showTweets).throttle(200);
       
   538     
       
   539     function getLocalTweets() {
       
   540     	
       
   541     	console.log("getLocalTweets");
       
   542     	
       
   543     	var topics = Array.prototype.join.call($(".topic.selected").map(function(){return $(this).attr("data-topic-id")})).split(",");
       
   544     	
       
   545     	for (var i = 0; i < localMmsos.length; i++) {
       
   546     		var mmso = data.segments[localMmsoDelta + i];
       
   547     		if (!tweetstructure[mmso.id]) {
       
   548     			tweetstructure[mmso.id] = {}
       
   549     		}
       
   550     		var mmsostruct = tweetstructure[mmso.id];
       
   551     		for (var j = 0; j < topics.length; j++) {
       
   552 				var topicid = topics[j],
       
   553 					weight = data.topics[topics[j]].weights[localMmsoDelta + i];
       
   554 				if (weight > .1 && !mmsostruct[topicid]) {
       
   555 					mmsostruct[topicid] = {
       
   556 						topic: topicid,
       
   557 						mmso: mmso.id,
       
   558 						status: 0,
       
   559 						weight: weight,
       
   560 						tweetids: []
       
   561 					};
       
   562 				}
       
   563     		}
   377     	}
   564     	}
   378     	
   565     	
   379     	function loadTweets() {
   566     	throttledGetTweetIds();
   380     		console.log("Tweet IDs retrieved",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date()));
   567     	throttledShowTweets();
   381     		var u = _.keys(tweetids);
   568     }
   382 			$.getJSON(
   569     
   383 				solrUrl(
   570     var throttledGetTweets = _.throttle(getLocalTweets, 500),
   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);
   571     	throttledShowLocal = _.throttle(showLocal, 100);
   467     
   572     
   468     showTopics(sortedTopics);
   573     showTopics(sortedTopics);
   469     (topicHash.match(/\d+/g) || []).forEach(function(id) {
   574     (topicHash.match(/\d+/g) || []).forEach(function(id) {
   470     	$(".topic[data-topic-id=" + id + "]").addClass("selected").attr("data-timestamp",++ordertag);
   575     	$(".topic[data-topic-id=" + id + "]").addClass("selected").attr("data-timestamp",++ordertag);
   489         showTopicViz();
   594         showTopicViz();
   490     });
   595     });
   491     
   596     
   492     var mouseIsDown, isDragging, startY, startT, startPos, scrollGlobal, speedscale, slowiterations;
   597     var mouseIsDown, isDragging, startY, startT, startPos, scrollGlobal, speedscale, slowiterations;
   493     
   598     
   494     function inertia() {
   599     $(document).mouseup(function() { mouseIsDown = false; isDragging = false; });
   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     
   600     
   509     $(".play-dataviz").mousedown(function(e) {
   601     $(".play-dataviz").mousedown(function(e) {
   510     	var l = $(this).offset().left,
   602     	var l = $(this).offset().left,
   511     		scrollLimit = l + 280;
   603     		scrollLimit = l + 380;
   512 		if (e.pageX < scrollLimit) {
   604 		if (e.pageX < scrollLimit) {
   513 			mouseIsDown = true;
   605 			mouseIsDown = true;
   514 	    	startY = e.pageY;
   606 	    	startY = e.pageY;
   515 	    	startT = new Date();
   607 	    	startT = new Date();
   516 	    	startPos = localpos;
   608 	    	startPos = localpos;
   534     		
   626     		
   535     		var posY = e.pageY - $(this).offset().top;
   627     		var posY = e.pageY - $(this).offset().top;
   536     		localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, Math.floor(posY / yscale)));
   628     		localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, Math.floor(posY / yscale)));
   537 			throttledShowLocal();
   629 			throttledShowLocal();
   538     	}
   630     	}
   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     });
   631     });
   549     
   632     
   550     var totalScroll = 0, zoomlevels = [ 1800, 900, 600, 300, 120, 60 ], currentlevel = 2;
   633     var totalScroll = 0, zoomlevels = [ 1800, 900, 600, 300, 120, 60 ], currentlevel = 2;
   551     
   634     
   552     $(".play-dataviz").mousewheel(function(_event, _scrolldelta) {
   635     $(".play-dataviz").mousewheel(function(_event, _scrolldelta) {