diff -r 239f91ac1f31 -r 698e4280d270 tweetcast/nodejs-bis/client/js/script.js --- a/tweetcast/nodejs-bis/client/js/script.js Tue Nov 22 18:33:51 2011 +0100 +++ b/tweetcast/nodejs-bis/client/js/script.js Wed Nov 23 18:49:52 2011 +0100 @@ -5,19 +5,18 @@ var socket, tlPaper, twCx = { - zoomLevel : 1, followLast : true, position : "0", date_levels : [ + 3600 * 1000, 15 * 60 * 1000, 5 * 60 * 1000, - 60 * 1000, - 15 * 1000 + 60 * 1000 ], - timeLevel : 0, + timeLevel : 1, deltaX : 40, tlWidth : 150, - tlHeight : 450, + tlHeight : 480, globalWords : {}, refMouse : { x : 0, y : 0}, refPosTl : { x : 0, y : 0}, @@ -29,7 +28,7 @@ relHover = [], wheelDelta = 0, scrollEnabled = false, - scrollExtent = 8000 - 452, + scrollExtent = 8000 - 480, lastScrollPos = 0, rx_url = /https?:\/\/[0-9a-zA-Z\.%\/-_]+/g, rx_word = /[^ \.&;,'"!\?\d\(\)\+\[\]\\\…\-«»:\/]{3,}/g, @@ -170,8 +169,14 @@ } function trimFDS() { - var centralTweet = ( twCx.centralTweet ? twCx.centralTweet : twCx.tweets[twCx.tweets.length - 1] ) - slices = flattenDateStruct(twCx.timeline, twCx.timeLevel), + var slices = flattenDateStruct(twCx.timeline, twCx.timeLevel); + while (slices[0].tweets.length == 0) { + slices.splice(0,1); + } + while (slices[slices.length - 1].tweets.length == 0) { + slices.pop(); + } + var centralTweet = ( twCx.centralTweet ? twCx.centralTweet : twCx.tweets[twCx.tweets.length - 1] ), delta = 30 * twCx.date_levels[twCx.timeLevel], centre = Math.min(slices[slices.length - 1].end - delta , Math.max(slices[0].start + delta, centralTweet.date_value)), min = centre - delta, @@ -235,16 +240,21 @@ } function goToPos(nPos) { - twCx.position = twCx.idIndex[Math.min( twCx.tweets.length - 1, Math.max(0, nPos ) )]; - twCx.followLast = (nPos == twCx.tweets.length - 1); + twCx.position = twCx.currentIdIndex[Math.min( twCx.currentIdIndex.length - 1, Math.max(0, nPos ) )]; + twCx.followLast = (!twCx.filtre && nPos == twCx.tweets.length - 1); updateDisplay(); } function movePos(delta) { - goToPos( delta + twCx.idIndex.indexOf(twCx.position) ); + goToPos( delta + twCx.currentIdIndex.indexOf(twCx.position) ); } function tweetToHtml(tweet, className, elName) { + + function highlight(texte) { + return ( twCx.filtre ? texte.replace(twCx.filtre, '$1' ) : texte ); + } + if (!tweet) { return placeHolder(className); } @@ -261,12 +271,12 @@ if (tweet.annotations.length) { html += '
'; for (var i in tweet.annotations) { - html += '
'; + html += '
'; } html += '
'; } html += '
'; - a_user = ''; + a_user = ''; html += '
' + a_user + ''; if (className == 'full') { html += '

' + new Date(tweet.date_value).toTimeString().substr(0,8) + '

'; @@ -280,7 +290,8 @@ entities.push({ "start" : tweet.entities.hashtags[i].indices[0], "end" : tweet.entities.hashtags[i].indices[1], - "html" : '#' + tweet.entities.hashtags[i].text + '' + "link" : '', + "text" : '#' + tweet.entities.hashtags[i].text }); } for (var i in tweet.entities.urls) { @@ -292,23 +303,30 @@ entities.push({ "start" : tweet.entities.urls[i].indices[0], "end" : tweet.entities.urls[i].indices[1], - "html" : '' + dispurl + '' + "link" : '', + "text" : dispurl }); } for (var i in tweet.entities.user_mentions) { entities.push({ "start" : tweet.entities.user_mentions[i].indices[0], "end" : tweet.entities.user_mentions[i].indices[1], - "html" : '@' + tweet.entities.user_mentions[i].screen_name + '' + "link" : '', + "text" : '@' + tweet.entities.user_mentions[i].screen_name }); } entities.sort(function(a, b) { return a.start - b.start }); for (var i in entities) { - txt += tweet.text.substring(lastend, entities[i].start) + entities[i].html; + txt += highlight( tweet.text.substring(lastend, entities[i].start) ) + entities[i].link + highlight( entities[i].text ) + ''; lastend = entities[i].end; } - txt += tweet.text.substring(lastend); - html += '

' + a_user + '@' + tweet.user.screen_name + ': ' + txt + '

'; + txt += highlight( tweet.text.substring(lastend) ); + html += '

' + a_user + highlight('@' + tweet.user.screen_name) + '' + ( className == 'full' ? ' (' + tweet.user.name + ')
' : ' : ') + txt + '

'; + if (className == 'full' && el == 'li') { + html += '
répondre · '; + html += 'retweeter · '; + html += 'favori
'; + } } html += '
'; return html; @@ -341,6 +359,9 @@ } function tlPosTweet(tweet, annotation) { + if (!twCx.tweets) { + return; + } var x, y, dt = tweet.date_value, @@ -437,11 +458,15 @@ } function updateDisplay() { - + if (!twCx.tweets) { + return; + } if (twCx.filtre) { var tweets = twCx.tweets.filter(function(tweet) { - return ( tweet.text.search(twCx.filtre) != -1 ) || ( tweet.user.screen_name.search(twCx.filtre) != -1 ) + var mention = '@' + tweet.user.screen_name; + return ( tweet.text.search(twCx.filtre) != -1 ) || ( mention.search(twCx.filtre) != -1 ); }); + $("#inp_q").val(twCx.filtreTexte + ' (' + tweets.length + ' tweets)'); if (tweets.length) { var idIndex = tweets.map(function(tweet) { return tweet.id; @@ -451,10 +476,12 @@ for (p = idIndex.length - 1; p > 0 && idIndex[p] > twCx.position; p--) { } } - console.log(p); + twCx.position = idIndex[p]; + twCx.currentIdIndex = idIndex; } } else { + twCx.currentIdIndex = twCx.idIndex; var tweets = twCx.tweets; var p = twCx.idIndex.indexOf(twCx.position); if (p == -1) { @@ -547,45 +574,49 @@ /* Recherche des mots pertinents correspondant à la sélection */ - for (var j in localWords) { - if (localWords[j].freq < 2) delete localWords[j]; - } - var tab = []; - for (var j in localWords) { - tab.push({ - "word": j, - "freq" : localWords[j].freq, - "annotations" : localWords[j].annotations, - "score" : localWords[j].freq / Math.log(1+twCx.globalWords[j]) - }); + var tab = _(localWords).map(function(v, k) { + return { + "word": k, + "freq" : v.freq, + "annotations" : v.annotations, + "score" : v.freq / Math.log( 2 + twCx.globalWords[j] ) + }; + }).filter(function(v) { + return v.freq > 1; + }); + + if (tab.length) { + + tab = _(tab).sortBy( function(a) { return ( - a.score ) }).slice(0,20); + var minfreq = _(tab).min( function(a) { return a.freq} ).freq, + maxfreq = Math.max(minfreq + .1, _(tab).max( function(a) { return a.freq} ).freq), + echfreq = 8 / Math.sqrt( maxfreq - minfreq ), + html = ''; + for (var j in tab) { + var maxann = 0, + ann = "default"; + for (var k in tab[j].annotations) { + if (tab[j].annotations[k] == maxann) { + ann = "default"; + } + if (tab[j].annotations[k] > maxann) { + ann = k; + maxann = tab[j].annotations[k]; + } + } + if (ann == "default") { + var coul = ''; + } else { + var c = getColor(ann, .6), + coul = "background: rgba(" + [ Math.floor(c.r), Math.floor(c.g), Math.floor(c.b), ( tab[j].annotations[ann] / tab[j].freq )].join(',') + ")"; + } + var fontsize = Math.floor( ( 12 + Math.sqrt( tab[j].freq - minfreq ) * echfreq ) ); + html += '' + tab[j].word + ' '; + } + $("#motscles").html(html); + } else { + $("#motscles").html(''); } - tab.sort( function(a,b){ return ( b.score - a.score ) }).splice(20); - var minfreq = tab[tab.length - 1].score, - maxfreq = Math.max(minfreq + .1, tab[0].score), - echfreq = 8 / Math.sqrt( maxfreq - minfreq ), - html = ''; - for (var j in tab) { - var maxann = 0, - ann = "default"; - for (var k in tab[j].annotations) { - if (tab[j].annotations[k] == maxann) { - ann = "default"; - } - if (tab[j].annotations[k] > maxann) { - ann = k; - maxann = tab[j].annotations[k]; - } - } - if (ann == "default") { - var coul = ''; - } else { - var c = getColor(ann, .6), - coul = "background: rgba(" + [ Math.floor(c.r), Math.floor(c.g), Math.floor(c.b), ( tab[j].annotations[ann] / tab[j].freq )].join(',') + ")"; - } - var fontsize = Math.floor( ( 12 + Math.sqrt( tab[j].score - minfreq ) * echfreq ) ); - html += '' + tab[j].word + ' '; - } - $("#motscles").html(html); twCx.centralTweet = tweets[p]; } else { $("#tweetlist").html(''); @@ -700,7 +731,7 @@ var yy = posp.y - .5 * twCx.scaleY, path = "M0 " + ppy + "C" + ( .7 * twCx.deltaX ) + " " + ppy + " " + ( .2 * twCx.deltaX ) + " " + yy + " " + ( twCx.deltaX ) + " " + yy + "L" + ( posp.x - .5 * twCx.scaleX ) + " " + yy; yy = posp.y + .5 * twCx.scaleY; - ppy += 84; + ppy += 117; path += "L" + ( posp.x - .5 * twCx.scaleX ) + " " + yy + "L" + twCx.deltaX + " " + yy + "C" + ( .2 * twCx.deltaX ) + " " + yy + " " + ( .7 * twCx.deltaX ) + " " + ppy + " 0 " + ppy; tlPaper.path( path ).attr({"stroke":"#ffff00", "fill" : "#ffff00", "fill-opacity" : .15}); @@ -709,11 +740,25 @@ } } -function filtrer(valeur) { - twCx.filtreTexte = valeur; - $("#inp_q").val(valeur).attr("class","rechercheCourante"); - twCx.filtre = ( valeur ? new RegExp(valeur.replace(/(\W)/g, '\\$1'),'ig') : null ); - twCx.followLast = !valeur && (twCx.position == twCx.idIndex[twCx.tweets.length - 1]); +function filtrerAnnotation(annotation) { + if (annotations[annotation]) { + effectuerFiltrage(annotations[annotation].display_name, + new RegExp( "(" + annotations[annotation].keywords.map(function(a) { return a.source }).join("|") + ")", "gi" ) ); + } else { + effectuerFiltrage('', null) + } +} + +function filtrerTexte(valeur) { + effectuerFiltrage( valeur, valeur ? new RegExp("(" + valeur.replace(/(\W)/g, '\\$1') + ")" ,'gi') : null ); +} + +function effectuerFiltrage(filtreTexte, tabRegexp) { + $("#recherche_annot").slideUp(); + $("#inp_q").val(filtreTexte).attr("class","rechercheCourante"); + twCx.filtreTexte = filtreTexte; + twCx.filtre = tabRegexp; + twCx.followLast = !tabRegexp && (twCx.position == twCx.idIndex[twCx.idIndex.length - 1]); updateDisplay(); } @@ -755,17 +800,36 @@ } function focusOutRecherche() { + $("#recherche_annot").slideUp(); var inpq = $("#inp_q"), val = inpq.val(); if (val == '' || val == twCx.filtreTexte) { if (twCx.filtre) { inpq.attr("class", "rechercheCourante").val(twCx.filtreTexte); } else { - inpq.attr("class", "greyed").val("Rechercher dans les tweets"); + inpq.attr("class", "greyed").val("Rechercher"); } } } +function chaineTimeZoom() { + var chaine = "", + t = twCx.date_levels[twCx.timeLevel], + h = 3600*1000, + m = 60*1000, + s = 1000, + heures = Math.floor(t/h); + if (heures) { chaine += heures + ' h. ' }; + t -= (heures * h); + var minutes = Math.floor(t/m); + if (minutes) { chaine += minutes + ' min. ' }; + t -= (minutes * m); + if (t) { chaine += Math.floor(t/s) + ' sec.' } + $("#time_scale").html(chaine); + $("#time_zoomout").attr("class",(twCx.timeLevel == 0 ? "inactive" : "")); + $("#time_zoomin").attr("class",(twCx.timeLevel == twCx.date_levels.length - 1 ? "inactive" : "")); +} + $(document).ready(function() { tlPaper = Raphael("timeline", twCx.tlWidth, twCx.tlHeight); @@ -791,6 +855,15 @@ $.getScript("tweetdata.js"); } + var html = ''; + for (var j in annotations) { + if (j != "default") { + html += '' + annotations[j].display_name + ' ' + } + } + $("#rech_list_annot").html(html); + + chaineTimeZoom(); $("#tweetlist").mousewheel(function(e, d) { wheelDelta += d; @@ -810,12 +883,27 @@ } if (tl != twCx.timeLevel) { twCx.timeLevel = tl; + chaineTimeZoom(); updateDisplay(); } wheelDelta = 0; } return false; }); + $("#time_zoomin").click(function() { + if (twCx.timeLevel < twCx.date_levels.length - 1) { + twCx.timeLevel++; + chaineTimeZoom(); + updateDisplay(); + } + }); + $("#time_zoomout").click(function() { + if (twCx.timeLevel > 0) { + twCx.timeLevel--; + chaineTimeZoom(); + updateDisplay(); + } + }); $("#timeline, #tweetlist").mouseout(function() { twCx.tlMouseClicked = false; twCx.tlMouseMoved = false; @@ -838,6 +926,8 @@ twCx.tlMouseMoved = false; }); $("#inp_q").focus(function() { + $("#recherche_annot").slideDown(); + $(this).val($(this).val().replace(/ \(.+\)$/, '')) if ($(this).hasClass("greyed")) { $(this).val(""); } @@ -847,25 +937,28 @@ focusOutRecherche(); }); $("#inp_reset").click(function() { + $("#inp_q").val(''); if (twCx.filtre) { twCx.filtre = null; updateDisplay(); } + twCx.filtreTexte = ''; focusOutRecherche(); return false; }) - $("#recherche").submit(function() { + $("#recherche").submit(function(evt) { + evt.preventDefault(); if (!$("#inp_q").hasClass("greyed")) { var valeur = $("#inp_q").val(); - filtrer(valeur); + filtrerTexte(valeur); } return false; }); setInterval(function() { var sc = $("#scrollcont"); - if (sc.scrollTop() != lastScrollPos) { - var p = Math.floor( twCx.tweets.length * ( 1 - sc.scrollTop() / scrollExtent ) ); + if (sc.scrollTop() != lastScrollPos && twCx.tweets) { + var p = Math.floor( twCx.currentIdIndex.length * ( 1 - sc.scrollTop() / scrollExtent ) ); goToPos(p); }