tweetcast/nodejs-bis/client/js/script.js
changeset 390 239f91ac1f31
parent 385 886bfa7441d0
child 391 698e4280d270
--- a/tweetcast/nodejs-bis/client/js/script.js	Tue Nov 22 18:22:37 2011 +0100
+++ b/tweetcast/nodejs-bis/client/js/script.js	Tue Nov 22 18:33:51 2011 +0100
@@ -7,7 +7,7 @@
     twCx = {
         zoomLevel : 1,
         followLast : true,
-        position : 0,
+        position : "0",
         date_levels : [
             15 * 60 * 1000,
             5 * 60 * 1000,
@@ -22,7 +22,8 @@
         refMouse : { x : 0, y : 0},
         refPosTl : { x : 0, y : 0},
         tlMouseMoved : false,
-        tlMouseClicked : false
+        tlMouseClicked : false,
+        filtre : null
         },
     tlBuffer = '',
     relHover = [],
@@ -169,9 +170,10 @@
 }
 
 function trimFDS() {
-    var slices = flattenDateStruct(twCx.timeline, twCx.timeLevel),
+    var centralTweet = ( twCx.centralTweet ? twCx.centralTweet : twCx.tweets[twCx.tweets.length - 1] )
+        slices = flattenDateStruct(twCx.timeline, twCx.timeLevel),
         delta = 30 * twCx.date_levels[twCx.timeLevel],
-        centre = Math.min(slices[slices.length - 1].end - delta , Math.max(slices[0].start + delta, twCx.tweets[twCx.position].date_value)),
+        centre = Math.min(slices[slices.length - 1].end - delta , Math.max(slices[0].start + delta, centralTweet.date_value)),
         min = centre - delta,
         max = centre + delta;
     while (slices[0].start < min) {
@@ -227,22 +229,19 @@
 }
 
 function selectTweet(tweetid) {
-    var pos = twCx.idIndex.indexOf(tweetid);
-    if (pos != -1) {
-        twCx.position = pos;
-        twCx.followLast = (twCx.position == twCx.tweets.length - 1);
-        updateDisplay()
-    }
+    twCx.position = tweetid;
+    twCx.followLast = (twCx.position == twCx.idIndex[twCx.tweets.length - 1]);
+    updateDisplay();
 }
 
 function goToPos(nPos) {
-    twCx.position = Math.min( twCx.tweets.length - 1, Math.max(0, nPos ) );
-    twCx.followLast = (twCx.position == twCx.tweets.length - 1);
+    twCx.position = twCx.idIndex[Math.min( twCx.tweets.length - 1, Math.max(0, nPos ) )];
+    twCx.followLast = (nPos == twCx.tweets.length - 1);
     updateDisplay();
 }
 
 function movePos(delta) {
-    goToPos( delta + twCx.position );
+    goToPos( delta + twCx.idIndex.indexOf(twCx.position) );
 }
 
 function tweetToHtml(tweet, className, elName) {
@@ -438,24 +437,44 @@
 }
 
 function updateDisplay() {
+    
+    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 )
+        });
+        if (tweets.length) {
+            var idIndex = tweets.map(function(tweet) {
+                return tweet.id;
+            });
+            var p = idIndex.indexOf(twCx.position);
+            if (p == -1) {
+                for (p = idIndex.length - 1; p > 0 && idIndex[p] > twCx.position; p--) {
+                }
+            }
+            console.log(p);
+        }
+        
+    } else {
+        var tweets = twCx.tweets;
+        var p = twCx.idIndex.indexOf(twCx.position);
+        if (p == -1) {
+            p = (twCx.followLast ? twCx.idIndex.length - 1 : 0);
+        }
+    }
 
-    var p = twCx.position,
-        l = twCx.tweets.length,
+    var l = tweets.length,
         lines = 0,
         ppy = 0,
         html = '',
         tweetsOnDisplay = [],
         localWords = {};
     
-    lastScrollPos = Math.floor( scrollExtent * ( 1 - ( p / twCx.tweets.length ) ) );
-    $("#scrollcont").scrollTop(lastScrollPos);
-    
     function pushTweet(tp, className) {
         if (tp < l && tp >= 0) {
-            html += tweetToHtml(twCx.tweets[tp], className)
+            html += tweetToHtml(tweets[tp], className)
             tweetsOnDisplay.push(tp);
-            for (var i in twCx.tweets[tp].words) {
-                var w = twCx.tweets[tp].words[i];
+            for (var i in tweets[tp].words) {
+                var w = tweets[tp].words[i];
                 if (localWords[w]) {
                     localWords[w].freq++
                 } else {
@@ -469,8 +488,8 @@
                         }
                     }
                 }
-                for (var j in twCx.tweets[tp].annotations) {
-                    localWords[w].annotations[twCx.tweets[tp].annotations[j]]++;
+                for (var j in tweets[tp].annotations) {
+                    localWords[w].annotations[tweets[tp].annotations[j]]++;
                 }
             }
         } else {
@@ -478,102 +497,119 @@
         }
     }
     
-    if (l > p + 18) {
-        lines++;
-        ppy += 20;
-        for (var i = p + 31; i >= p + 18; i--) {
-            pushTweet(i, 'icons');
-        }
-    }
-    if (l > p + 4) {
-        lines++;
-        ppy += 20;
-        for (var i = p + 17; i >= p + 4; i--) {
-            pushTweet(i, 'icons');
-        }
-    }
-    for (var k = 3; k >= 1; k--) {
-        if (l > p + k) {
-            ppy += 47;
+    if (l) {
+    
+        lastScrollPos = Math.floor( scrollExtent * ( 1 - ( p / l ) ) );
+        $("#scrollcont").scrollTop(lastScrollPos);
+        
+        if (l > p + 18) {
             lines++;
-            pushTweet(p + k, 'half');
-        }
-    }
-    pushTweet(p, 'full');
-    var n = p - 1;
-    for (var i = 0; i < Math.min(6, Math.max(3, 6 - lines)); i++) {
-        if (n < 0) {
-            break;
-        }
-        pushTweet(n, 'half');
-        n--;
-    }
-    for (var i = 0; i < 14 * Math.min(4, Math.max(2, 7 - lines)); i++) {
-        if (n < 0) {
-            break;
+            ppy += 20;
+            for (var i = p + 31; i >= p + 18; i--) {
+                pushTweet(i, 'icons');
+            }
         }
-        pushTweet(n, 'icons');
-        n--;
-    }
-    if (html != tlBuffer) {
-        $("#tweetlist").html(html);
-        $(".tweet.full").fadeIn();
-        tlBuffer = html;
-    }
-    
-    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])
-        });
-    }
-    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 (l > p + 4) {
+            lines++;
+            ppy += 20;
+            for (var i = p + 17; i >= p + 4; i--) {
+                pushTweet(i, 'icons');
             }
-            if (tab[j].annotations[k] > maxann) {
-                ann = k;
-                maxann = tab[j].annotations[k];
+        }
+        for (var k = 3; k >= 1; k--) {
+            if (l > p + k) {
+                ppy += 47;
+                lines++;
+                pushTweet(p + k, 'half');
             }
         }
-        if (ann == "default") {
-            var coul = '';
-        } else {
-            var c = getColor(ann, .4),
-                coul = "background: rgba(" + [ Math.floor(c.r), Math.floor(c.g), Math.floor(c.b), ( tab[j].annotations[ann] / tab[j].freq )].join(',') + ")";
+        pushTweet(p, 'full');
+        var n = p - 1;
+        for (var i = 0; i < Math.min(6, Math.max(3, 6 - lines)); i++) {
+            if (n < 0) {
+                break;
+            }
+            pushTweet(n, 'half');
+            n--;
+        }
+        for (var i = 0; i < 14 * Math.min(4, Math.max(2, 7 - lines)); i++) {
+            if (n < 0) {
+                break;
+            }
+            pushTweet(n, 'icons');
+            n--;
+        }
+        if (html != tlBuffer) {
+            $("#tweetlist").html(html);
+            $(".tweet.full").fadeIn();
+            tlBuffer = html;
+        }
+        
+        /* Recherche des mots pertinents correspondant à la sélection */
+        
+        for (var j in localWords) {
+            if (localWords[j].freq < 2) delete localWords[j];
         }
-        var fontsize = Math.floor( ( 12 + Math.sqrt( tab[j].score - minfreq ) * echfreq ) );
-        html += '<span style="padding: 2px; line-height: ' + (8 + fontsize) + 'px; font-size: ' + fontsize + 'px;' + coul + '">' + tab[j].word + '</span> ';
+        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])
+            });
+        }
+        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 += '<span style="line-height: ' + (8 + fontsize) + 'px; font-size: ' + fontsize + 'px;' + coul + '" onclick="filtrer(\'' + tab[j].word.replace(/('|")/g, '\\$1') + '\')">' + tab[j].word + '</span> ';
+        }
+        $("#motscles").html(html);
+        twCx.centralTweet = tweets[p];
+    } else {
+        $("#tweetlist").html('');
+        tlBuffer = '';
+        $("#motscles").html('');
     }
-    $("#motscles").html(html);
     
     twCx.tlOnDisplay = trimFDS();
     twCx.scaleY = twCx.tlHeight / twCx.tlOnDisplay.length;
     var maxTweets = 0,
         startTl = 0,
-        endTl = twCx.tlOnDisplay.length - 1,
-        startTw = twCx.tweets[tweetsOnDisplay[tweetsOnDisplay.length - 1]].date_value,
-        endTw = twCx.tweets[tweetsOnDisplay[0]].date_value;
+        endTl = twCx.tlOnDisplay.length - 1;
+    if (l) {
+        var startTw = tweets[tweetsOnDisplay[tweetsOnDisplay.length - 1]].date_value,
+            endTw = tweets[tweetsOnDisplay[0]].date_value;
+    }
     for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
-        if (startTw >= twCx.tlOnDisplay[i].start && startTw < twCx.tlOnDisplay[i].end) {
-            startTl = i;
-        }
-        if (endTw >= twCx.tlOnDisplay[i].start && endTw < twCx.tlOnDisplay[i].end) {
-            endTl = i;
+        if (l) {
+            if (startTw >= twCx.tlOnDisplay[i].start && startTw < twCx.tlOnDisplay[i].end) {
+                startTl = i;
+            }
+            if (endTw >= twCx.tlOnDisplay[i].start && endTw < twCx.tlOnDisplay[i].end) {
+                endTl = i;
+            }
         }
         var displayData = {};
         for (var j in annotations) {
@@ -605,31 +641,31 @@
     relHover = null;
     
     // Dessin de la correspondance liste-timeline
-    
-    var startY = twCx.tlHeight - startTl * twCx.scaleY,
-        endY = twCx.tlHeight - ( endTl + 1 ) * twCx.scaleY,
-        path = "M0 " + twCx.tlHeight + "C" + .7*twCx.deltaX + " " + twCx.tlHeight + " " + .3*twCx.deltaX + " " + startY + " " + twCx.deltaX + " " + startY + "L" + twCx.tlWidth + " " + startY + "L" + twCx.tlWidth + " " + endY + "L" + twCx.deltaX + " " + endY + "C" + .3*twCx.deltaX + " " + endY + " " + .7*twCx.deltaX + " 0 0 0";
-    tlPaper.path( path ).attr({ "stroke" : "none", "fill" : "#000080", "opacity" : .2 });
-        
+    if (l) {
+        var startY = twCx.tlHeight - startTl * twCx.scaleY,
+            endY = twCx.tlHeight - ( endTl + 1 ) * twCx.scaleY,
+            path = "M0 " + twCx.tlHeight + "C" + .7*twCx.deltaX + " " + twCx.tlHeight + " " + .3*twCx.deltaX + " " + startY + " " + twCx.deltaX + " " + startY + "L" + twCx.tlWidth + " " + startY + "L" + twCx.tlWidth + " " + endY + "L" + twCx.deltaX + " " + endY + "C" + .3*twCx.deltaX + " " + endY + " " + .7*twCx.deltaX + " 0 0 0";
+        tlPaper.path( path ).attr({ "stroke" : "none", "fill" : "#000080", "opacity" : .2 });
+    }   
     // dessin de la date de début
     
-    tlPaper.text(2, twCx.tlHeight - 7, new Date(twCx.tlOnDisplay[0].start).toTimeString().substr(0,5))
-        .attr({ "text-anchor" : "start", "font-size": "9px" });
+    tlPaper.text(twCx.deltaX / 2, twCx.tlHeight - 7, new Date(twCx.tlOnDisplay[0].start).toTimeString().substr(0,5))
+        .attr({ "text-anchor" : "middle", "font-size": "9px" });
     
     // dessin de la date de fin
     
-    tlPaper.text(2, 7, new Date(twCx.tlOnDisplay[twCx.tlOnDisplay.length - 1].end).toTimeString().substr(0,5))
-        .attr({ "text-anchor" : "start", "font-size": "9px" });
+    tlPaper.text(twCx.deltaX / 2, 7, new Date(twCx.tlOnDisplay[twCx.tlOnDisplay.length - 1].end).toTimeString().substr(0,5))
+        .attr({ "text-anchor" : "middle", "font-size": "9px" });
     
     for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
         var n = 0,
             posY = twCx.tlHeight - ( i + 1 ) * twCx.scaleY;
         for (var j in twCx.tlOnDisplay[i].displayData) {
-            var l = twCx.tlOnDisplay[i].displayData[j].length;
-            if (l > 0) {
-                tlPaper.rect( twCx.deltaX + n * twCx.scaleX, posY, l * twCx.scaleX, twCx.scaleY )
+            var ll = twCx.tlOnDisplay[i].displayData[j].length;
+            if (ll > 0) {
+                tlPaper.rect( twCx.deltaX + n * twCx.scaleX, posY, ll * twCx.scaleX, twCx.scaleY )
                     .attr({"stroke" : "none", "fill" : getColor(j, .4).hex });
-                n += l;
+                n += ll;
             }
         }
         
@@ -637,27 +673,48 @@
         
         if (i < twCx.tlOnDisplay.length - 1 && !(twCx.tlOnDisplay[i].end % 1800000)) {
             tlPaper.path("M0 "+posY+"L" + twCx.tlWidth +" "+posY).attr({"stroke":"#ccc"});
-            tlPaper.text(2, posY, new Date(twCx.tlOnDisplay[i].end).toTimeString().substr(0,5)).attr({ "text-anchor" : "start", "font-size": "9px" });
+            tlPaper.text(twCx.deltaX / 2, posY, new Date(twCx.tlOnDisplay[i].end).toTimeString().substr(0,5)).attr({ "text-anchor" : "middle", "font-size": "9px" });
         }
     }
     
     // dessin du tweet courant
     
-    
-    var posp = tlPosTweet(twCx.tweets[p]);
-    if (posp) {
+    if (l) {
+        
+        if (twCx.filtre) {
+            for (var i = 0; i < tweets.length; i++) {
+                if (i != p) {
+                    var pos = tlPosTweet(tweets[i]);
+                    if (pos) {
+                        drawTweetPos(pos, "#ffccff");
+                    }
+                }
+            }
+            
+        }
         
-        drawTweetPos(posp, "#ffff00");
-        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;
-        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});
-        
-        drawTweetArcs(twCx.tweets[p], posp, '#800080');
+        var posp = tlPosTweet(tweets[p]);
+        if (posp) {
+            
+            drawTweetPos(posp, "#ffff00");
+            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;
+            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});
+            
+            drawTweetArcs(tweets[p], posp, '#800080');
+        }
     }
-    
+}
+
+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]);
+    updateDisplay();
 }
 
 function clicTl(evt) {
@@ -692,11 +749,23 @@
         addTweet(tweets[i]);
     }
     if (twCx.followLast) {
-        twCx.position = twCx.tweets.length - 1;
+        twCx.position = twCx.idIndex[twCx.tweets.length - 1];
     }
     updateDisplay();
 }
 
+function focusOutRecherche() {
+    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");
+        }
+    }
+}
+
 $(document).ready(function() {
     tlPaper = Raphael("timeline", twCx.tlWidth, twCx.tlHeight);
     
@@ -714,7 +783,7 @@
                 addTweet(data.new_tweets[i]);
             }
             if (twCx.followLast) {
-                twCx.position = twCx.tweets.length - 1;
+                twCx.position = twCx.idIndex[twCx.tweets.length - 1];
             }
             updateDisplay();
         });
@@ -761,13 +830,38 @@
         twCx.tlMouseMoved = false;
         var o = $(this).offset();
         twCx.refMouse = { x : evt.pageX - o.left, y : evt.pageY - o.top };
-        twCx.refPosTl = tlPosTweet(twCx.tweets[twCx.position]) || twCx.refMouse;
+        twCx.refPosTl = tlPosTweet(tweetById(twCx.position)) || twCx.refMouse;
     });
     $("#timeline").mouseup(function(evt) {
         clicTl(evt);
         twCx.tlMouseClicked = false;
         twCx.tlMouseMoved = false;
     });
+    $("#inp_q").focus(function() {
+        if ($(this).hasClass("greyed")) {
+            $(this).val("");
+        }
+        $(this).attr("class","");
+    });
+    $("#inp_q").focusout(function() {
+        focusOutRecherche();
+    });
+    $("#inp_reset").click(function() {
+        if (twCx.filtre) {
+            twCx.filtre = null;
+            updateDisplay();
+        }
+        focusOutRecherche();
+        return false;
+    })
+    $("#recherche").submit(function() {
+        if (!$("#inp_q").hasClass("greyed")) {
+            var valeur = $("#inp_q").val();
+            filtrer(valeur);
+        }
+        return false;
+    });
+    
     setInterval(function() {
         var sc = $("#scrollcont");
         if (sc.scrollTop() != lastScrollPos) {