--- a/tweetcast/nodejs-bis/client/js/script.js Tue Nov 15 11:38:14 2011 +0100
+++ b/tweetcast/nodejs-bis/client/js/script.js Tue Nov 15 18:29:44 2011 +0100
@@ -18,12 +18,17 @@
deltaX : 30,
tlWidth : 98,
tlHeight : 450,
- globalWords : {}
+ globalWords : {},
+ refMouse : { x : 0, y : 0},
+ refPosTl : { x : 0, y : 0},
+ tlMouseMoved : false,
+ tlMouseClicked : false
},
tlBuffer = '',
relHover = null,
wheelDelta = 0,
- rx_word = /[^ \.&;,'"!\?@#\d\(\)\+\[\]\\\…\-«»:\/]{3,}/g;
+ rx_word = /[^ \.&;,'"!\?@#\d\(\)\+\[\]\\\…\-«»:\/]{3,}/g,
+ stop_list = [ 'and', 'les', 'the' ];
function arc(source, target) {
var x3 = .3 * target.y - .3 * source.y + .8 * source.x + .2 * target.x;
@@ -34,13 +39,15 @@
}
function countWords(text, wordobj) {
- var tab = text.match(rx_word);
+ var tab = text.replace(/https?:\/\/[0-9a-zA-Z\.%\/-_]+/g,'').match(rx_word);
for (var i in tab) {
var word = tab[i].toLowerCase();
- if (wordobj[word]) {
- wordobj[word]++;
- } else {
- wordobj[word] = 1;
+ if (stop_list.indexOf(word) == -1 && tracking_keywords.indexOf(word) == -1) {
+ if (wordobj[word]) {
+ wordobj[word]++;
+ } else {
+ wordobj[word] = 1;
+ }
}
}
}
@@ -61,12 +68,26 @@
}
}
- var tab = tweet.text.split(/\&\#|\;/),
- txt = '';
- for (i = 0; i < tab.length; i++) {
- txt += (i % 2 && parseInt(tab[i]) != NaN) ? String.fromCharCode(tab[i]) : tab[i];
+ var ann = [];
+ for (var j in annotations) {
+ if (j != "default") {
+ for (var k in annotations[j].keywords) {
+ if (tweet.text.search(annotations[j].keywords[k]) != -1) {
+ ann.push(j);
+ break;
+ }
+ }
+ }
}
- tweet.text = txt;
+ tweet.annotations = ann;
+
+ var tab = tweet.text.match(/\&\#[0-9]+\;/g);
+ for (var i in tab) {
+ var n = parseInt(tab[i].substr(2));
+ if (n != NaN) {
+ tweet.text = tweet.text.replace(tab[i], String.fromCharCode(n ));
+ }
+ }
twCx.tweets.push(tweet);
twCx.idIndex.push(tweet.id);
@@ -80,7 +101,7 @@
countWords(tweet.text, twCx.globalWords);
- var creadate = new Date(tweet.created_at).valueOf();
+ var creadate = tweet.date_value;
if (!twCx.timeline.length) {
twCx.timeline = [ populateDateStruct(0, twCx.date_levels[0] * parseInt(creadate / twCx.date_levels[0])) ]
}
@@ -155,7 +176,7 @@
}
function insertIntoDateStruct(slices, tweet) {
- var creadate = new Date(tweet.created_at).valueOf();
+ var creadate = tweet.date_value;
for (var i in slices) {
if (creadate < slices[i].end) {
if (slices[i].slices) {
@@ -212,7 +233,7 @@
a_user = '<a href="http://twitter.com/' + tweet.user.screen_name + '" var target="_blank" title="' + tweet.user.name + '">';
html += '<div class="around_img">' + a_user + '<img class="profile_image" src="' + tweet.user.profile_image_url + '" /></a>';
if (className == 'full') {
- html += '<p class="created_at">' + new Date(tweet.created_at).toLocaleTimeString() + '</p>';
+ html += '<p class="created_at">' + new Date(tweet.date_value).toLocaleTimeString() + '</p>';
}
html += '</div>';
if (className != 'icons') {
@@ -252,15 +273,16 @@
return html;
}
-function tlIdFromPos(x, y) {
- if (x < twCx.deltaX) {
- return null;
- }
- var ligne = Math.floor(( twCx.tlHeight - y ) / twCx.scaleY),
+function tlIdFromPos(x, y, outside) {
+ var ligne = Math.min( twCx.tlOnDisplay.length - 1, Math.max( 0, Math.floor(( twCx.tlHeight - y ) / twCx.scaleY) ) ),
colonne = Math.floor(( x - twCx.deltaX ) / twCx.scaleX ),
l = 0;
- if (colonne >= twCx.tlOnDisplay[ligne].totalTweets) {
- return null;
+ if (colonne >= twCx.tlOnDisplay[ligne].totalTweets || colonne < 0 ) {
+ if (outside) {
+ colonne = Math.min( twCx.tlOnDisplay[ligne].totalTweets - 1, Math.max( 0, colonne ));
+ } else {
+ return null;
+ }
}
for (var i in twCx.tlOnDisplay[ligne].displayData) {
var nl = l + twCx.tlOnDisplay[ligne].displayData[i].length;
@@ -277,7 +299,7 @@
function tlPosTweet(tweet, annotation) {
var x,
y,
- dt = new Date(tweet.created_at).valueOf(),
+ dt = tweet.date_value,
ann = ( annotation ? annotation : ( tweet.annotations.length ? tweet.annotations[0] : 'default' ) );
for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
if (twCx.tlOnDisplay[i].end > dt) {
@@ -318,7 +340,7 @@
function drawTweetPos(pos, color) {
var rel = tlPaper.rect(pos.x - .5 * twCx.scaleX, pos.y - .5 * twCx.scaleY, twCx.scaleX, twCx.scaleY);
- rel.attr({ "stroke" : color });
+ rel.attr({ "stroke" : color, "fill" : color, "fill-opacity" : .1 });
return rel;
}
@@ -326,6 +348,7 @@
var p = twCx.position,
l = twCx.tweets.length,
lines = 0,
+ ppy = 0,
html = '',
tweetsOnDisplay = [],
localWords = {};
@@ -342,18 +365,21 @@
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;
lines++;
pushTweet(p + k, 'half');
}
@@ -387,19 +413,22 @@
for (var j in localWords) {
tab.push({
"word": j,
- "freq" : localWords[j] / Math.log(twCx.globalWords[j])
+ "freq" : localWords[j] / Math.log(1+twCx.globalWords[j])
});
}
- tab.sort( function(a,b){ return b.freq - a.freq }).splice(10);
- $("#motscles").html(tab.map(function(t) { return t.word }).join(", "))
+ tab.sort( function(a,b){ return ( b.freq - a.freq ) }).splice(15);
+ var minfreq = tab[tab.length - 1].freq,
+ maxfreq = Math.max(minfreq + .1, tab[0].freq),
+ echfreq = 8 / Math.sqrt( maxfreq - minfreq );
+ $("#motscles").html(tab.map(function(t) { return '<span style="font-size: ' + Math.floor( ( 12 + Math.sqrt( t.freq - minfreq ) * echfreq ) ) + 'px">' + t.word + '</span>' }).join(" "))
twCx.tlOnDisplay = trimFDS(flattenDateStruct(twCx.timeline, twCx.timeLevel));
twCx.scaleY = twCx.tlHeight / twCx.tlOnDisplay.length;
var maxTweets = 0,
startTl = 0,
endTl = 0,
- startTw = new Date(twCx.tweets[tweetsOnDisplay[tweetsOnDisplay.length - 1]].created_at).valueOf(),
- endTw = new Date(twCx.tweets[tweetsOnDisplay[0]].created_at).valueOf();
+ startTw = twCx.tweets[tweetsOnDisplay[tweetsOnDisplay.length - 1]].date_value,
+ endTw = twCx.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;
@@ -436,6 +465,13 @@
tlPaper.clear();
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 });
+
// dessin de la date de début
tlPaper.text(2, twCx.tlHeight - 7, new Date(twCx.tlOnDisplay[0].start).toTimeString().substr(0,5))
@@ -466,19 +502,19 @@
}
}
- // Dessin de la correspondance liste-timeline
+ // dessin du tweet courant
- var startY = twCx.tlHeight - startTl * twCx.scaleY,
- endY = twCx.tlHeight - ( endTl + 1 ) * twCx.scaleY;
- tlPaper.path("M0 " + twCx.tlHeight + "L" + twCx.deltaX + " " + startY + "L" + twCx.tlWidth + " " + startY + "L" + twCx.tlWidth + " " + endY + "L" + twCx.deltaX + " " + endY + "L0 0" )
- .attr({ "stroke" : "none", "fill" : "#000080", "opacity" : .1 });
- // dessin du tweet courant
-
var posp = tlPosTweet(twCx.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" : .2});
// dessin des liens entre tweets
@@ -517,6 +553,30 @@
}
+function clicTl(evt) {
+ var o = $("#timeline").offset();
+ if (twCx.tlMouseClicked && twCx.tlMouseMoved) {
+ var twid = tlIdFromPos(evt.pageX - o.left + twCx.refPosTl.x - twCx.refMouse.x, evt.pageY - o.top + twCx.refPosTl.y - twCx.refMouse.y, true);
+ if (twid) {
+ selectTweet(twid.id);
+ }
+ } else {
+ var twid = tlIdFromPos(evt.pageX - o.left, evt.pageY - o.top, twCx.tlMouseClicked);
+ if (twCx.tlMouseMoved && !twCx.tlMouseClicked) {
+ if (twid) {
+ rolloverTweet(twid.id, twid.annotation);
+ } else {
+ $("#hovertweet").hide();
+ }
+ }
+ if (twCx.tlMouseClicked && !twCx.tlMouseMoved) {
+ if (twid) {
+ selectTweet(twid.id);
+ }
+ }
+ }
+}
+
$(document).ready(function() {
tlPaper = Raphael("timeline", twCx.tlWidth, twCx.tlHeight);
socket = io.connect('http://' + document.location.hostname );
@@ -570,20 +630,24 @@
return false;
});
$("#timeline, #tweetlist").mouseout(function() {
+ twCx.tlMouseClicked = false;
+ twCx.tlMouseMoved = false;
$("#hovertweet").hide();
});
$("#timeline").mousemove(function(evt) {
- var twid = tlIdFromPos(evt.offsetX, evt.offsetY);
- if (twid) {
- rolloverTweet(twid.id, twid.annotation);
- } else {
- $("#hovertweet").hide();
- }
+ twCx.tlMouseMoved = true;
+ clicTl(evt);
});
- $("#timeline").click(function(evt) {
- var twid = tlIdFromPos(evt.offsetX, evt.offsetY);
- if (twid) {
- selectTweet(twid.id);
- }
+ $("#timeline").mousedown(function(evt) {
+ twCx.tlMouseClicked = true;
+ 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;
+ });
+ $("#timeline").mouseup(function(evt) {
+ clicTl(evt);
+ twCx.tlMouseClicked = false;
+ twCx.tlMouseMoved = false;
});
});
\ No newline at end of file
--- a/tweetcast/nodejs-bis/tweetcast.js Tue Nov 15 11:38:14 2011 +0100
+++ b/tweetcast/nodejs-bis/tweetcast.js Tue Nov 15 18:29:44 2011 +0100
@@ -6,7 +6,7 @@
eval(fs.readFileSync(conf_file,'utf8'));
tweet_file = flagOption('-f', (typeof tweet_file == "undefined" ? 'tweets.txt' : tweet_file ));
-tracking_keyword = flagOption('-t', (typeof tracking_keyword == "undefined" ? null : tracking_keyword ));
+tracking_keyword = flagOption('-t', (typeof tracking_keywords == "undefined" ? null : tracking_keywords.join(",") ));
user_pass = flagOption('-u', (typeof user_pass == "undefined" ? null : user_pass ));
if (!user_pass) {
@@ -75,18 +75,27 @@
'profile_background_color',
'profile_background_tile',
'utc_offset'
- ];
+ ],
+ content_types = {
+ css : "text/css",
+ html : "text/html",
+ js : "text/javascript",
+ png : "image/png"
+ };
function httpHandler(req, res) {
console.log("HTTP Request for URL "+req.url);
- var url = ( req.url == "/config" ? conf_file : __dirname + "/client" + req.url + ( req.url[req.url.length - 1] == "/" ? "index.html" : "" ) );
+ var url = ( req.url == "/config" ? conf_file : __dirname + "/client" + req.url + ( req.url[req.url.length - 1] == "/" ? "index.html" : "" ) ),
+ ext = url.split('.').slice(-1)[0].toLowerCase();
fs.readFile( url, function(err, data) {
if (err) {
console.log("Error 404");
res.writeHead(404);
return res.end('File not found');
}
- res.writeHead(200);
+ res.writeHead(200, {
+ "Content-Type" : ( content_types[ext] ? content_types[ext] : 'text/plain' )
+ });
res.end(data);
});
}
@@ -101,6 +110,7 @@
console.log("Error: Tweet already in list");
return false;
}
+ tweet.date_value = new Date(tweet.created_at).valueOf();
tweets.push(tweet);
tweet_ids.push(tweet.id);
return true;
@@ -163,19 +173,7 @@
try {
for (var i in newdata) {
if (newdata[i].length > 0) {
- var tweet = JSON.parse(newdata[i]),
- ann = [];
- for (var j in annotations) {
- if (j != "default") {
- for (var k in annotations[j].keywords) {
- if (tweet.text.search(annotations[j].keywords[k]) != -1) {
- ann.push(j);
- break;
- }
- }
- }
- }
- tweet.annotations = ann;
+ var tweet = JSON.parse(newdata[i]);
textids(tweet);
for (var j in keys_to_delete) {
delete tweet[keys_to_delete[j]];
@@ -206,7 +204,7 @@
});
});
- req.write('track=' + encodeURIComponent((tracking_keyword)));
+ req.write('track=' + encodeURIComponent( ( tracking_keyword ) ) );
req.end();
}