# HG changeset patch # User veltr # Date 1366211443 -7200 # Node ID 8b0a464fb5ac7caf00143ca6dceac0efa3e5760e # Parent 685c406c7d8cc917930ff4538919ae6b3d4a68b1 Changed drawing from SVG to Canvas diff -r 685c406c7d8c -r 8b0a464fb5ac css/playscreen.css --- a/css/playscreen.css Tue Apr 16 18:26:43 2013 +0200 +++ b/css/playscreen.css Wed Apr 17 17:10:43 2013 +0200 @@ -96,7 +96,7 @@ background-position: -36px -18px; } -.play-svg { +.play-canvas { position: absolute; left: 0; top: 0; width: 100%; height: 100%; } @@ -187,9 +187,14 @@ } .play-tagcloud li { - float: left; width: 98px; height: 10px; - line-height: 10px; - text-align: center; cursor: pointer; + cursor: pointer; + float: left; + height: 16px; + line-height: 16px; + text-align: center; + width: 98px; + display: inline-block; + margin-bottom: -6px; } .play-tagcloud li.selected { @@ -204,19 +209,6 @@ margin-top: 10px; } -.local-position, .global-position { - position: absolute; height: 1px; - background: #FF00FC; -} - -.global-position { - left: 0; width: 125px; -} - -.local-position { - left: 155px; width: 215px; -} - .user-tweets { position: absolute; left: 730px; top: 300px; bottom: 0; right: 0; display: none; } diff -r 685c406c7d8c -r 8b0a464fb5ac js/playscreen.js --- a/js/playscreen.js Tue Apr 16 18:26:43 2013 +0200 +++ b/js/playscreen.js Wed Apr 17 17:10:43 2013 +0200 @@ -223,20 +223,77 @@ tb.html(tbhtml); tb.css("top",0); - showTopicViz(); + throttledShowLocal(); } + + + + var images = {}, + playTime = $(".current-time"); + + var globW = 85, + globL = 40, + entonnoirR = 155, + localL = 235, + localW = 85, + localR = (localL + localW), + localTimeR = (localL + localW) + globL, + globR = (globW + globL), + mx = Math.max.apply(Math, data.minutes.map(function(s) { return s.count})), + xscale = globW/mx, + yscale, + localyscale, + filteredSegments = []; - var tweetLines = []; - - function showTopicViz() { + function showLocal() { + var $c = $(".play-canvas"), + c = $c[0], + ph = $c.height(), + pw = $c.width(); + + yscale = ph / data.duration; + localyscale = ph / localduration; + + var localstart = localpos - localduration/2; + localend = localpos + localduration/2; + globtop = yscale * localstart, + globbottom = yscale * localend, + betweenx = (globR + entonnoirR) / 2, + betweenyt = (globtop) / 2, + betweenyb = (globbottom + ph) / 2, + curve = (entonnoirR - globR) / 2, + + c.width = pw; + c.height = ph; + + var ctx = c.getContext('2d'); + + ctx.clearRect(0,0, pw, ph); + + /* Tracé de l'entonnoir */ + + ctx.beginPath(); + + ctx.moveTo(0, globtop); + ctx.lineTo(globR, globtop); + ctx.quadraticCurveTo(betweenx, globtop, betweenx, Math.max(globtop - curve, betweenyt)); + ctx.lineTo(betweenx, Math.min(curve, betweenyt)); + ctx.quadraticCurveTo(betweenx, 0, entonnoirR, 0 ); + ctx.lineTo(localR,0); + ctx.lineTo(localR, ph); + ctx.lineTo(entonnoirR, ph); + ctx.quadraticCurveTo(betweenx, ph, betweenx, Math.max(ph - curve, betweenyb)); + ctx.lineTo(betweenx, Math.min(globbottom + curve, betweenyb)); + ctx.quadraticCurveTo(betweenx, globbottom, globR, globbottom, globbottom); + ctx.lineTo(0,globbottom); + ctx.fillStyle = '#222222'; + ctx.fill(); + + var selectedBlocks = $(".topic.selected, .topic.hover"), sbl = selectedBlocks.length, - topicBlocks = $(".topic"); - if (!sbl && topicBlocks.length < sortedTopics.length) { - selectedBlocks = topicBlocks; - sbl = selectedBlocks.length; - } - var topicsAndColors = [], + topicBlocks = $(".topic"), + topicsAndColors = [], colors = {}; selectedBlocks.each(function() { var el = $(this), @@ -258,259 +315,223 @@ colors[topic.id] = topic.color; topic.$.css("background", topic.color); }); - + + /* Tracé des MMSOs */ + + var localkeywords = {}; + + filteredSegments = []; + for (var i = 0; i < nmmso; i++) { - var opacity = 0, + var mmso = data.segments[i], + 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; + var o = topic.topic.weights[i]; + rgb[0] += parseInt(topic.color.substr(1,2),16) * o; + rgb[1] += parseInt(topic.color.substr(3,2),16) * o; + rgb[2] += parseInt(topic.color.substr(5,2),16) * o; opacity += o; }); + var isinlocal = (mmso.end > localstart && mmso.start < localend); + if (isinlocal) { + filteredSegments.push(mmso); + var y = localyscale * (mmso.start - localstart), + h = localyscale * mmso.duration, + visibled = ( + mmso.start < localstart + ? mmso.duration - localstart + mmso.start + : ( + mmso.end > localend + ? mmso.duration - mmso.end + localend + : mmso.duration + ) + ); + _(mmso.keywords).each(function(v,k) { + localkeywords[k] = (v * visibled) + (localkeywords[k] || 0); + }); + } 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(); + rgb = rgb.map(function(c) { + return parseInt(c/opacity); + }); + ctx.fillStyle = 'rgba(' + rgb.join(',') + ',' + opacity + ')'; + ctx.fillRect(globL, yscale * mmso.start, globW, yscale * mmso.duration); + if (isinlocal) { + ctx.fillRect( localL, y, localW, h ); } } } - tweetLines.forEach(function(tl) { tl.remove(); }); - tweetLines = []; + /* Tracé des courbes de nombres de tweets */ + + var styles = [ + { + lineWidth: 4, + strokeStyle: "rgba(0,0,0,.5)" + }, + { + lineWidth: 1, + strokeStyle: "#ffffff" + } + ] + + styles.forEach(function(s) { + ctx.beginPath(); + data.minutes.forEach(function(m, i) { + var x = globL + xscale * m.count, + y1 = yscale * (m.from + 20), + y2 = yscale * (m.from + 40); + if (i) { + ctx.lineTo(x,y1); + } else { + ctx.moveTo(x,y1); + } + ctx.lineTo(x,y2); + }); + _(s).each(function(v, k) { + ctx[k] = v; + }); + ctx.stroke(); + }); + + 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); + + styles.forEach(function(s) { + ctx.beginPath(); + filteredFiveSecs.forEach(function(m, i) { + var x = localL + lxscale * (m.count - lmi), + y1 = localyscale * (m.from + 1 - localstart), + y2 = localyscale * (m.from + 4 - localstart); + if (i) { + ctx.lineTo(x,y1); + } else { + ctx.moveTo(x,y1); + } + ctx.lineTo(x,y2); + }); + _(s).each(function(v, k) { + ctx[k] = v; + }); + ctx.stroke(); + }); var deltaY = $(".play-bottom").offset().top; $(".play-localtweets .tweet:visible").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 + "L400," + liY, - path = paper.path(p); + tY = localyscale * (+el.attr("data-timestamp") - localpos + localduration / 2); + ctx.beginPath(); + ctx.strokeStyle = "#ccc"; + ctx.moveTo(localL, tY); + ctx.lineTo(localR, tY); + ctx.lineTo(400, liY); + ctx.stroke(); $(this).css("background",colors[el.attr("data-topic-id")] || ""); - path.attr({ - stroke: "#ccc" - }); - tweetLines.push(path); }); - } - - var jqsvg = $(".play-svg"), - paper = new Raphael(jqsvg[0]), - totalR = jqsvg.width(), - ph = jqsvg.height(), - globW = 85, - globL = 40, - entonnoirR = 155, - localL = 235, - 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"); + ctx.fillStyle = '#ffffff'; + ctx.strokeStyle = '#999999'; + ctx.font = '10px Arial,Helvetica'; + + function line(x1,y1,x2,y2) { + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + } - 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(); - - var cloudTemplate = _.template('
  • class="selected"<% } %>><%- word %>
  • '); - - var globalIndic = $(".global-position"), - localIndic = $(".local-position"), - playTime = $(".current-time"); - - function showLocal() { - localyscale = ph / localduration; - var localstart = localpos - localduration/2; - localend = localpos + localduration/2; - globtop = yscale * localstart, - globbottom = yscale * localend, - betweenx = (globR + entonnoirR) / 2, - betweenyt = (globtop) / 2, - betweenyb = (globbottom + ph) / 2, - curve = (entonnoirR - 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," + entonnoirR + ",0" - + "L" + localR + ",0L" + localR + "," + ph + "L" + entonnoirR + "," + ph + "Q" + betweenx + "," + ph + "," - + betweenx + "," + Math.max(ph - curve, betweenyb) +"L" + betweenx + "," + Math.min(globbottom + curve, betweenyb) - + "Q" + betweenx + "," + globbottom + "," + globR + "," + globbottom + "L0," + globbottom, - localkeywords = {}; - - entonnoir.attr("path",entonnoird); - localIndic.css("top",(player.currentTime - localstart) * localyscale); - 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, - rect = paper.rect( localL, y, localW, h ), - visibled = ( - s.start < localstart - ? s.duration - localstart + s.start - : ( - s.end > localend - ? s.duration - s.end + localend - : s.duration - ) - ); - _(s.keywords).each(function(v,k) { - localkeywords[k] = (v * visibled) + (localkeywords[k] || 0); - }); - rect.attr({stroke: "none", title: s.id}); - if (parseInt(s.id.replace("MMSO_","")) % 2) { - var altrect = paper.rect( localR, y, 60, h); - altrect.attr({stroke: "none", fill: "#222"}); - mmsoAlt.push(altrect); - } - return rect; - }); - localStartText.attr("text", secsToString(localstart)).toFront(); - localEndText.attr("text", secsToString(localend)).toFront(); + line(0, 0, localTimeR, 0); + line(0, ph-1, localTimeR, ph-1 ); + line(globR, 0, globR, ph); + line(localL, 0, localL, ph); + + /* Global Times */ + ctx.fillText(secsToString(data.duration), 0, ph - 3); + + for (var i=0; i < data.duration; i += 1800) { + var y = yscale * i; + line(0, y, globR, y); + ctx.fillText(secsToString(i), 0, y+9); + } + + /* Local Times */ + ctx.fillText(secsToString(localstart), localTimeR - 30, 9); + ctx.fillText(secsToString(localend), localTimeR - 30, ph - 3); + 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 y = localyscale*(i - localstart); + ctx.fillText(secsToString(i), localTimeR - 30, 9+y); + line(localL, y, localTimeR, y); } - 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" - }); - - var imghtm = '', imgrate = localduration / 12, imgstart = imgrate * Math.floor(localstart / imgrate), imgend = imgrate * Math.ceil(localend / imgrate); - for (var i = imgstart; i <= imgend; i+= imgrate) { + + + var imgw = 80, + imgh = 45, + imgrate = localduration / 12, + imgstart = imgrate * Math.floor(localstart / imgrate), + imgend = imgrate * Math.ceil(localend / imgrate); + + for (var i = imgstart; i <= imgend; i+= imgrate) { var imgsrc = i + '.png'; while (imgsrc.length < 9) { imgsrc = '0' + imgsrc; } - var imgy = Math.floor( localyscale * (i - localstart) - 22.5 ) - imghtm += ''; + if (images[i]) { + if (images[i].width) { + ctx.drawImage(images[i], entonnoirR, localyscale * (i - localstart) - imgh / 2, imgw, imgh); + } + } else { + var img = new Image(); + img.onload = function() { + throttledShowLocal(); + } + img.src = 'thumbnails/' + imgsrc; + images[i] = img; + } } - $(".play-images").html(imghtm); + if (player) { + var yg = yscale * player.currentTime, + yl = (player.currentTime - localstart) * localyscale, + betweeny = (yg + yl) / 2, + styles = [ + { + lineWidth: 4, + strokeStyle: "rgba(0,0,0,.5)" + }, + { + lineWidth: 1, + strokeStyle: "#ff00cc" + } + ]; + + styles.forEach(function(s) { + ctx.beginPath(); + ctx.moveTo(0, yg); + if (player.currentTime >= localstart && player.currentTime <= localend) { + ctx.lineTo(globR, yg); + ctx.quadraticCurveTo(betweenx + 3, yg, betweenx + 3, yg > yl ? Math.max(yg - curve, betweeny) : Math.min(yg + curve, betweeny)); + ctx.lineTo(betweenx + 3, yg < yl ? Math.max(yl - curve, betweeny) : Math.min(yl + curve, betweeny)); + ctx.quadraticCurveTo(betweenx + 3, yl, entonnoirR + 6, yl ); + ctx.lineTo(localR, yl); + } else { + ctx.lineTo(betweenx, yg); + } + + _(s).each(function(v, k) { + ctx[k] = v; + }); + ctx.stroke(); + }); + + } + $(".play-localtweets .tweet").each(function() { var el = $(this), t = parseInt(el.attr("data-timestamp")); @@ -529,36 +550,56 @@ .sortBy(function(w) { return -w.score; }) - .first(40) + .first(39) .value(); var values = _(localkeywords).pluck('score'), max = Math.max.apply(Math, values), min = Math.min.apply(Math, values), scale = 10 / (max - Math.min(max - .1, min)), - selectedVisible = false; - - localkeywords.forEach(function(w) { - w.size = 10 + (w.score - min) * scale; - w.selected = (w.word === selectedWord); - selectedVisible = selectedVisible || w.selected; + selectedVisible = false, + tc = $(".play-tagcloud li"); + + localkeywords.forEach(function(w, i) { + var size = 10 + (w.score - min) * scale, + selected = (w.word === selectedWord), + e = $(tc[i]), + t = e.text(); + if (t !== w.word) { + e.text(w.word); + } + e.css("font-size", size + "px"); + if (selected) { + e.addClass("selected"); + } else { + e.removeClass("selected"); + } + selectedVisible = selectedVisible || selected; }); + if (localkeywords.length < 39) { + for (var i = localkeywords.length; i < 39; i++) { + $(tc[i]).text("").removeClass("selected"); + } + } if (!selectedVisible) { selectedWord = false; } - - $(".play-tagcloud").html(localkeywords.map(cloudTemplate).join("")); - + throttledGetTweets(); - showTopicViz(); + } + + for (var i = 0; i < 39; i++) { + $(".play-tagcloud").append("
  • "); } - $(".play-tagcloud").on("click","li", function() { - if ($(this).hasClass("selected")) { + $(".play-tagcloud li").click(function() { + + var w = $(this).text(); + if (w === selectedWord) { selectedWord = false; } else { - selectedWord = $(this).text(); + selectedWord = w; } throttledShowLocal(); }); @@ -584,8 +625,7 @@ var toshow = []; var topics = Array.prototype.join.call($(".topic.selected").map(function(){return $(this).attr("data-topic-id")})).split(","); - for (var i = 0; i < localMmsos.length; i++) { - var mmso = data.segments[localMmsoDelta + i]; + filteredSegments.forEach(function(mmso) { var mmsostruct = tweetstructure[mmso.id]; if (mmsostruct) { for (var j = 0; j < topics.length; j++) { @@ -598,7 +638,7 @@ } } } - } + }); toshow = _(toshow).uniq(); var tweetstoshow = toshow.map(function(tid) { @@ -677,7 +717,7 @@ h += $(this).outerHeight(); }); $(".play-localtweets .tweet").css("margin-top",Math.max(0,($(".play-bottom").height() - h)/(tweetstoshow.length+1))); - showTopicViz(); + showLocal(); } @@ -801,23 +841,22 @@ var topics = Array.prototype.join.call($(".topic.selected").map(function(){return $(this).attr("data-topic-id")})).split(","); - for (var i = 0; i < localMmsos.length; i++) { - var mmso = data.segments[localMmsoDelta + i]; + filteredSegments.forEach(function(mmso) { if (!tweetstructure[mmso.id]) { tweetstructure[mmso.id] = { mmsoid: mmso.id, - mmsoindex: localMmsoDelta + i, + mmsoindex: parseInt(mmso.id.replace(/^\w+_/,'')), status: 0 } } - } + }); throttledGetTweetIds(); throttledShowTweets(); } var throttledGetTweets = _.throttle(getLocalTweets, 500), - throttledShowLocal = _.throttle(showLocal, 100); + throttledShowLocal = _.throttle(showLocal, 50); showTopics(sortedTopics); @@ -840,15 +879,10 @@ }); player.on("timeupdate", function(t) { playTime.text(secsToString(t)); - globalIndic.css("top", yscale * t); - if (localyscale) { - var localy = (+t - localpos + localduration / 2) * localyscale; - localIndic.css("top", localy); - } if (timelock) { localpos = Math.max(localduration / 2, Math.min(data.duration - localduration / 2, t)); - throttledShowLocal(); } + throttledShowLocal(); }); $(".play-button").click(function() { @@ -873,16 +907,16 @@ $(".topics-list").on("mouseenter", ".topic", function() { var el = $(this); el.addClass("hover"); - showTopicViz(); + throttledShowLocal(); }).on("mouseleave", ".topic", function() { $(this).removeClass("hover"); - showTopicViz(); + throttledShowLocal(); }).on("click", ".topic", function() { var el = $(this); $(this).toggleClass("selected"); el.attr("data-timestamp", el.hasClass("selected") ? ++ordertag : 999999); throttledGetTweets(); - showTopicViz(); + throttledShowLocal(); }); var h = Hammer($(".play-bottom")[0]); @@ -1048,6 +1082,8 @@ return false; }); + $(window).on("resize", throttledShowLocal) + checkOrGoNext(); } diff -r 685c406c7d8c -r 8b0a464fb5ac playscreen-frame.html --- a/playscreen-frame.html Tue Apr 16 18:26:43 2013 +0200 +++ b/playscreen-frame.html Wed Apr 17 17:10:43 2013 +0200 @@ -45,18 +45,13 @@
    -
    -
    -
    -
    -
    -
      -
        -
        -

        Tweets par

        -
          -
          -
          + + + +
          +

          Tweets par

          +
            +
            Ouvrir la fenêtre TV @@ -69,7 +64,6 @@ - diff -r 685c406c7d8c -r 8b0a464fb5ac playscreen.html --- a/playscreen.html Tue Apr 16 18:26:43 2013 +0200 +++ b/playscreen.html Wed Apr 17 17:10:43 2013 +0200 @@ -44,10 +44,7 @@
            -
            -
            -
            -
            +
            @@ -65,7 +62,6 @@ -