diff -r 26a901771957 -r 490e4d1b6fee js/playscreen.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/playscreen.js Wed Mar 06 18:09:40 2013 +0100 @@ -0,0 +1,689 @@ +var topicPoubelle = 13; + +var adjust = 54; + +var deltaT = new Date("Wed, 02 May 2012 19:00:00 +0000") / 1000 + adjust; + +function solrUrl(table, params) { + return "http://159.217.144.101:8050/sia-solr/" + table + "/select?" + $.param(params) + "&wt=json&json.wrf=?"; +} + +function showData() { + + var topicHash = document.location.hash || "#topics=5,15"; + + var ordertag = 0; + + function secsToString(seconds) { + var hours = Math.floor(seconds/3600), + minutes = Math.floor(seconds/60) % 60, + secs = Math.floor(seconds % 60); + function pad(n) { + var r = n.toString(); + while (r.length < 2) { + r = "0" + r; + } + return r; + } + return (hours ? (hours + ":") : "") + pad(minutes) + ":" + pad(secs); + } + + $(".duration").text(secsToString(data.duration)); + + var nmmso = data.segments.length; + + data.topics.forEach(function(topic) { + topic.score = 0; + topic.weights = []; + for (var i = 0; i < nmmso; i++) { + topic.weights.push(0); + } + }); + + data.segments.forEach(function(mmso, i) { + mmso.topics.forEach(function(t) { + data.topics[t.topic].weights[i] = t.weight; + data.topics[t.topic].score += t.weight; + }); + }); + + var sortedTopics = data.topics.filter(function(t) { + return t.index !== topicPoubelle; + }).sort(function(a,b) { + return b.score - a.score; + }); + + + function showTopics(topiclist) { + var tbhtml = topiclist.reduce(function(mem, topic) { + var wordsToShow = topic.words.slice(0,3), + max = wordsToShow[0].weight, + min = Math.min(wordsToShow[wordsToShow.length - 1].weight, max - .01), + scale = 8 / (max - min); + var li = '
  • '; + return mem + li; + },''); + var tb = $(".topics-block"); + tb.html(tbhtml); + tb.css("top",0); + + showTopicViz(); + } + + var tweetLines = []; + + function showTopicViz() { + var selectedBlocks = $(".topic.selected, .topic.hover"), + sbl = selectedBlocks.length, + topicBlocks = $(".topic"); + if (!sbl && topicBlocks.length < sortedTopics.length) { + selectedBlocks = topicBlocks; + sbl = selectedBlocks.length; + } + var topicsAndColors = [], + colors = {}; + selectedBlocks.each(function() { + var el = $(this), + topicid = parseInt(el.attr("data-topic-id")); + topicsAndColors.push({ + "$": el, + timestamp: parseInt(el.attr("data-timestamp")), + hovered: el.hasClass("hover"), + id: topicid, + topic: data.topics[topicid] + }); + }); + topicsAndColors.sort(function(a,b) { + return ( a.timestamp - b.timestamp ) || ( a.id - b.id ); + }); + topicBlocks.css("background",""); + topicsAndColors.forEach(function(topic, i) { + topic.color = topic.hovered ? "#ffff00" : colorset[i % colorset.length]; + colors[topic.id] = topic.color; + topic.$.css("background", topic.color); + }); + + for (var i = 0; i < nmmso; i++) { + var opacity = 0, + rgb = [0,0,0]; + topicsAndColors.forEach(function(topic) { + var c = Raphael.getRGB(topic.color), + o = topic.topic.weights[i]; + rgb[0] += c.r * o; + rgb[1] += c.g * o; + rgb[2] += c.b * o; + opacity += o; + }); + if (opacity) { + color = Raphael.rgb.apply(Raphael, rgb.map(function(c) { + return c/opacity; + })); + var attr = { + fill: color, + opacity: .5 + .5 * opacity + }; + segmentrects[i].show(); + segmentrects[i].attr(attr); + if (i >= localMmsoDelta && i < localMmsoDelta + localMmsos.length) { + localMmsos[i - localMmsoDelta].show(); + localMmsos[i - localMmsoDelta].attr(attr); + } + } else { + segmentrects[i].hide(); + if (i >= localMmsoDelta && i < localMmsoDelta + localMmsos.length) { + localMmsos[i - localMmsoDelta].hide(); + } + } + } + + tweetLines.forEach(function(tl) { tl.remove(); }); + tweetLines = []; + + var deltaY = $(".play-dataviz").offset().top; + + $(".play-localtweets .tweet").each(function() { + var el = $(this), + liY = + el.offset().top + el.outerHeight() / 2 - deltaY, + tY = localyscale * (+el.attr("data-timestamp") - localpos + localduration / 2), + p = "M" + localL + "," + tY + "L" + localR + "," + tY + "L320," + liY, + path = paper.path(p); + $(this).css("background",colors[el.attr("data-topic-id")] || ""); + path.attr({ + stroke: "#ccc" + }); + tweetLines.push(path); + }); + throttledGetTweets(); + + } + + var jqsvg = $(".play-svg"), + paper = new Raphael(jqsvg[0]), + totalR = jqsvg.width(), + ph = jqsvg.height(), + globW = 85, + globL = 40, + localL = 155, + localW = 85, + localR = (localL + localW), + localTimeR = (localL + localW) + globL, + globR = (globW + globL), + yscale = ph / data.duration, + mx = Math.max.apply(Math, data.minutes.map(function(s) { return s.count})), + xscale = globW/mx; + + var segmentrects = data.segments.map(function(mmso) { + var rect = paper.rect(globL, yscale * mmso.start, globW, yscale * mmso.duration); + rect.attr({stroke: "none"}); + return rect; + }); + + var d = "M" + data.minutes.map(function(s) { + var x = globL + xscale * s.count; + return x + + "," + + yscale * (s.from + 20) + + "L" + + x + + "," + + yscale * (s.from + 40); + }).join("L"); + + paper.path(d).attr({ + "stroke-width": 4, + "stroke": "#000000", + opacity: .5 + }); + paper.path(d).attr({ + "stroke-width": 1, + "stroke": "#ffffff" + }); + + for (var i=0; i < data.duration; i += 1800) { + var y = yscale * i; + paper.path("M0" + "," + y + "l" + globR + ",0").attr({stroke: "#666"}); + paper.text(0, y + 6, secsToString(i)).attr({ + "text-anchor": "start", + "fill": "#ffffff" + }); + } + paper.text(0, ph-8, secsToString(data.duration)).attr({ + "text-anchor": "start", + "fill": "#ffffff" + }); + paper.path("M0" + globR + ",0L" + localTimeR + ",0" ).attr({stroke: "#666"}); + paper.path("M0," + (ph-1) + "l" + localTimeR + ",0" ).attr({stroke: "#666"}); + + paper.path("M" + globR + ",0l0," + ph).attr({stroke: "#666"}); + paper.path("M" + localL + ",0l0," + ph).attr({stroke: "#666"}); + + var entonnoir = paper.path("").attr("fill","#333"), + localStartText = paper.text(localTimeR,6,"").attr({ + "text-anchor": "end", + "fill": "#ffffff" + }), + localEndText = paper.text(localTimeR,ph - 8, "").attr({ + "text-anchor": "end", + "fill": "#ffffff" + }), + localTimes = [], + localMmsos = [], + localMmsoDelta, + mmsoAlt = [], + lowerFiveSecs, + higherFiveSecs, + localyscale; + + entonnoir.toBack(); + + function showLocal() { + localyscale = ph / localduration; + var localstart = localpos - localduration/2; + localend = localpos + localduration/2; + globtop = yscale * localstart, + globbottom = yscale * localend, + betweenx = (globR + localL) / 2, + betweenyt = (globtop) / 2, + betweenyb = (globbottom + ph) / 2, + curve = (localL - globR) / 2, + entonnoird = "M0," + globtop + "l" + globR + ",0Q" + betweenx + "," + globtop + "," + betweenx + "," + + Math.max(globtop - curve, betweenyt) + "L" + betweenx + "," + Math.min(curve, betweenyt) + "Q" + + betweenx + ",0," + localL + ",0" + + "L" + localR + ",0L" + localR + "," + ph + "L" + localL + "," + ph + "Q" + betweenx + "," + ph + "," + + betweenx + "," + Math.max(ph - curve, betweenyb) +"L" + betweenx + "," + Math.min(globbottom + curve, betweenyb) + + "Q" + betweenx + "," + globbottom + "," + globR + "," + globbottom + "L0," + globbottom; + + entonnoir.attr("path",entonnoird); + localTimes.forEach(function(t) { + t.text.remove(); + t.line.remove(); + }); + localMmsos.forEach(function(t) { + t.remove(); + }); + mmsoAlt.forEach(function(t) { + t.remove(); + }); + var filteredSegments = data.segments.filter(function(s) { + return s.start < localend && s.end > localstart; + }); + localMmsoDelta = parseInt(filteredSegments[0].id.split("_")[1]); + localMmsos = filteredSegments.map(function(s) { + var y = localyscale * (s.start - localstart), + h = localyscale * s.duration; + var rect = paper.rect( localL, y, localW, h ); + rect.attr({stroke: "none", title: s.id}); + if (parseInt(s.id.replace("MMSO_","")) % 2) { + var altrect = paper.rect( localR, y, (totalR - localR), h); + altrect.attr({stroke: "none", fill: "#222"}); + mmsoAlt.push(altrect); + } + return rect; + }); + localStartText.attr("text", secsToString(localstart)).toFront(); + localEndText.attr("text", secsToString(localend)).toFront(); + for ( var i = (1 + Math.floor(localstart / 120)) * 120; i < localend; i += 120 ) { + var y = localyscale*(i - localstart) + localTimes.push({ + text: paper.text(localTimeR,6+y,secsToString(i)).attr({ + "text-anchor": "end", + "fill": "#ffffff" + }), + line: paper.path("M0" + localL + "," + y + "L" + localTimeR + "," + y).attr({stroke: "#666"}) + }); + } + if (lowerFiveSecs) { + lowerFiveSecs.remove(); + } + if (higherFiveSecs) { + higherFiveSecs.remove(); + } + var filteredFiveSecs = data.fiveseconds.slice(Math.floor(localstart / 5), Math.ceil(localend / 5)); + var counts = filteredFiveSecs.map(function(s) { return s.count}), + lmx = Math.max.apply(Math, counts), + lmi = Math.min.apply(Math, counts.concat([lmx - 1])) + lxscale = localW/(lmx-lmi); + + var d = "M" + filteredFiveSecs.map(function(s) { + var x = localL + lxscale * (s.count - lmi); + return x + + "," + + localyscale * (s.from + 1 - localstart) + + "L" + + x + + "," + + localyscale * (s.from + 4 - localstart); + }).join("L"); + + lowerFiveSecs = paper.path(d).attr({ + "stroke-width": 4, + "stroke": "#000000", + opacity: .5 + }); + higherFiveSecs = paper.path(d).attr({ + "stroke-width": 1, + "stroke": "#ffffff" + }); + showTopicViz(); + } + + + var lastPos, lastDuration, lastTopics; + + var tweetTemplate = _.template('
  • @<%- from_user_name %>: <%- text %>

  • '), + callnum = 0; + + function getTweets() { + var topicIds = Array.prototype.join.call($(".topic.selected").map(function(){return $(this).attr("data-topic-id")})); + if (localduration === lastDuration && lastTopics === topicIds && Math.abs(localpos - lastPos) < (localduration / 10)) { + console.log("We already have these tweets, delta =", localpos - lastPos ); + return; + } + if (!topicIds) { + console.log("No topics selected"); + return; + } + var localcall = ++callnum; + console.log("getTweets was called",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date())); + var tweetids = {}, + rqtodo = 0, + rqdone = 0, + topics = topicIds.split(","); + + function getMmsoTopicTweets(mmsoid, topic, ntweets) { + rqtodo++; + TopicsBean.bestSocialInteractionsIdsMatching(mmsoid, topic, 0, ntweets, { + callback: function(tw) { + for (var k = 0; k < tw.length; k++) { + tweetids[tw[k]] = topic; + } + rqdone++; + if (rqdone === rqtodo) { + loadTweets(); + } + } + }); + } + + function loadTweets() { + console.log("Tweet IDs retrieved",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date())); + var u = _.keys(tweetids); + $.getJSON( + solrUrl( + "twitter", + { + q:"id:(" + u.join(" OR ") + ")", + rows: u.length + } + ), + function(t) { + console.log("Full tweets retrieved",localcall,(function(d){return d.toLocaleTimeString()+"."+d.getMilliseconds()})(new Date())); + var tweets = t.response.docs; + var s = 600 / (1+tweets.length); + tweets.forEach(function(tweet, i) { + tweet._date = new Date(tweet.created_at); + tweet._timestamp = tweet._date.valueOf() / 1000 - deltaT; + tweet._topic = tweetids[tweet.id_str] + }); + tweets.sort(function(a,b) { + return a._date - b._date; + }); + var html = tweets.reduce(function(mem, tweet) { + return mem + tweetTemplate(tweet); + },''); + $(".play-localtweets").html(html); + var h = 0; + $(".play-localtweets .tweet").each(function() { + h += $(this).outerHeight(); + }); + $(".play-localtweets .tweet").css("margin-top",Math.max(0,($(".play-bottom").height() - h)/(tweets.length+1))); + showTopicViz(); + } + ); + $(".play-localtweets").html(""); + showTopicViz(); + } + + function getMmsoTweets(nmmso) { + var mmso = data.segments[nmmso], + mmsopixels = localyscale * (Math.min(localpos + localduration / 2, mmso.end) - Math.max(localpos - localduration / 2, mmso.start)); + var ntweets = Math.floor(( 50 + mmsopixels ) / 80), + mmsotopics = []; + if (!ntweets) { + return; + } + for (var j = 0; j < topics.length; j++) { + var weight = data.topics[topics[j]].weights[nmmso]; + if (weight > .05) { + mmsotopics.push({topic:parseInt(topics[j]),weight:weight,ntweets:0}); + } + } + mmsotopics.sort(function(a,b){return b.weight - a.weight}); + if (mmsotopics.length) { + for (var j = 0; j < ntweets; j++) { + mmsotopics[j % mmsotopics.length].ntweets++; + } + mmsotopics = mmsotopics.filter(function(t) { return !!t.ntweets }); + for (var j = 0; j < mmsotopics.length; j++) { + getMmsoTopicTweets(mmso.id, mmsotopics[j].topic, mmsotopics[j].ntweets); + } + } else { + var t = [], m = {}; + while (t.length < ntweets) { + t = t.concat(topics); + } + for (var j = 0; j < ntweets; j++) { + m[t[j]] = 1 + (m[t[j]]||0); + } + _(m).each(function(v,k) { + getMmsoTopicTweets(mmso.id, k, v); + }); + } + } + + dwr.engine.beginBatch(); + for (var i = 0; i < localMmsos.length; i++) { + getMmsoTweets(localMmsoDelta + i); + } + dwr.engine.endBatch(); + lastPos = localpos; + lastDuration = localduration; + lastTopics = topicIds; + } + + var throttledGetTweets = _.throttle(_.debounce(getTweets, 500), 10000), + throttledShowLocal = _.throttle(showLocal, 100); + + showTopics(sortedTopics); + (topicHash.match(/\d+/g) || []).forEach(function(id) { + $(".topic[data-topic-id=" + id + "]").addClass("selected").attr("data-timestamp",++ordertag); + }); + + var localpos = 7100, + localduration = 600; + + showLocal(); + + $(".topics-block").on("mouseenter", ".topic", function() { + var el = $(this); + el.addClass("hover"); + showTopicViz(); + }).on("mouseleave", ".topic", function() { + $(this).removeClass("hover"); + showTopicViz(); + }).on("click", ".topic", function() { + var el = $(this); + $(this).toggleClass("selected"); + el.attr("data-timestamp", el.hasClass("selected") ? ++ordertag : 999999); + showTopicViz(); + }); + + var mouseIsDown, isDragging, startY, startT, startPos, scrollGlobal, speedscale, slowiterations; + + function inertia() { + startPos = localpos; + window.setTimeout(function() { + speedscale = .75 * speedscale; + localstart += 100*speedscale; + throttledShowLocal(); + if (slowiterations < 5) { + inertia(); + } + slowiterations++; + }, 100); + } + + $("body").mouseup(function() { mouseIsDown = false; }); + + $(".play-dataviz").mousedown(function(e) { + var l = $(this).offset().left, + scrollLimit = l + 280; + if (e.pageX < scrollLimit) { + mouseIsDown = true; + startY = e.pageY; + startT = new Date(); + startPos = localpos; + scrollGlobal = e.pageX < (l + 140); + e.preventDefault(); + } + }).mousemove(function(e) { + if (mouseIsDown) { + if (isDragging) { + var limit = $(this).offset().left + 140, + deltaY = e.pageY - startY, + delta = Math.floor(deltaY / (scrollGlobal ? yscale : - localyscale)); + localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, startPos + delta)); + throttledShowLocal(); + } else { + isDragging = true; + } + } + }).mouseup(function(e) { + if (scrollGlobal && !isDragging) { + + var posY = e.pageY - $(this).offset().top; + localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, Math.floor(posY / yscale))); + throttledShowLocal(); + } +/* if (isDragging) { + var limit = $(this).offset().left + 140, + deltaY = e.pageY - startY, + deltaT = new Date() - startT, + delta = Math.floor(deltaY / (scrollGlobal ? yscale : - localyscale)); + speedscale = delta / deltaT; + slowiterations = 0; + inertia(); + } */ + }); + + var totalScroll = 0, zoomlevels = [ 1800, 900, 600, 300, 120, 60 ], currentlevel = 2; + + $(".play-dataviz").mousewheel(function(_event, _scrolldelta) { + totalScroll += _scrolldelta; + if (Math.abs(totalScroll) >= 1) { + var d = (totalScroll > 0 ? 1 : -1), + newlevel = Math.max(0, Math.min(zoomlevels.length - 1, currentlevel + d)); + if (newlevel !== currentlevel) { + currentlevel = newlevel; + localduration = zoomlevels[currentlevel]; + localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, localpos)); + throttledShowLocal(); + } + totalScroll = 0; + } + }) + +} + +var data = { duration: 10200, topics: [] }, + colorset = ["#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#A65628", "#F781BF"]; + +$(function() { + + dwr.engine.setErrorHandler(function(a, b) { console.error("DWR", b); }); + + $(".topics-block").draggable({axis:"x"}); + + var loadedSteps = 0, + stepsToFullyLoaded = 0; + + function checkIfLoaded() { + loadedSteps++; + if (loadedSteps >= stepsToFullyLoaded) { + setTimeout(showData,0); + } + } + + function loadJson(url, propname, callback) { + stepsToFullyLoaded++; + $.getJSON(url, function(d) { + if (callback) { + var res = callback(d); + } else { + var res = d; + } + if (propname) { + data[propname] = res; + } + checkIfLoaded(); + }); + } + + function loadFromTopicsBean(method, propname, args, callback) { + stepsToFullyLoaded++; + var arg = args || [], + cb = function(d) { + if (callback) { + var res = callback(d); + } else { + var res = d; + } + if (propname) { + data[propname] = res; + } + checkIfLoaded(); + } + arg.push({callback: cb}); + TopicsBean[method].apply(TopicsBean,arg); + } + + loadJson("data/minutes.json", "minutes"); + loadJson("data/5secs.json", "fiveseconds"); + + loadJson( + solrUrl("MMSO", {q: "*:*", fl: "topic*,MMSO_id,multimediaSegment", rows: 250 }), + "segments", + function(d) { + return d.response.docs.map(function(mmso) { + var tc = mmso.multimediaSegment.match(/\d+/g), + start = parseInt(tc[0]), + end = parseInt(tc[1]), + topics = []; + for (var k in mmso) { + if (k.substr(0,5) === "topic" && mmso[k] > .01) { + topics.push({ + topic: parseInt(k.substr(5)), + weight: mmso[k] + }) + } + } + topics.sort(function(a,b) { + return b.weight - a.weight; + }); +/* topics = topics.filter(function(t) { + return t.topic !== topicPoubelle + }).slice(0,1); + topics[0].weight = 1; */ + return { + id: mmso.MMSO_id, + start: start, + end: end, + duration: end - start, + topics: topics + } + }).sort(function(a,b) { + return a.start - b.start; + }); + }) + + dwr.engine.setTimeout(60000); + TopicsBean._path = "http://159.217.144.101:8050/sia-solr/dwr"; + + loadFromTopicsBean("getTopicsNumber",false,false,function(topic_count) { + for (var i = 0; i < topic_count; i++) { + data.topics.push(null); + } + dwr.engine.beginBatch(); + data.topics.forEach(function(v, k) { + loadFromTopicsBean("getTopicDistribution",false,[k, 50, false],function(topic) { + var words = topic.match(/[^=,{]+=0.\d{0,8}/g); + data.topics[k] = { + index: k, + words: words.map(function(w) { + var parts = w.split("="); + return { + word: parts[0].trim(), + weight: parseFloat(parts[1]) + } + }) + } + }); + + }); + dwr.engine.endBatch(); + + }); + + +});