# HG changeset patch # User Raphael Velt # Date 1318947548 -7200 # Node ID c28048fb63b4e518bcbed1b0b4c95950564a9e98 # Parent 7d9c576bfaac68dddca4ddc175cb91798277206e Added visual timeline feature to node client diff -r 7d9c576bfaac -r c28048fb63b4 tweetcast/nodejs/client/css/style.css --- a/tweetcast/nodejs/client/css/style.css Mon Oct 17 17:40:58 2011 +0200 +++ b/tweetcast/nodejs/client/css/style.css Tue Oct 18 16:19:08 2011 +0200 @@ -113,4 +113,10 @@ .a_question { background: #bfdbec; +} + +/* timeline */ + +#timeline { + position: absolute; top: 50px; left: 291px; height: 600px; width: 160px; border: 1px solid #999; } \ No newline at end of file diff -r 7d9c576bfaac -r c28048fb63b4 tweetcast/nodejs/client/index.html --- a/tweetcast/nodejs/client/index.html Mon Oct 17 17:40:58 2011 +0200 +++ b/tweetcast/nodejs/client/index.html Tue Oct 18 16:19:08 2011 +0200 @@ -9,12 +9,15 @@ S_IO_PORT = 8000; document.write(' +

Niveau de zoom (liste de tweets) 1 - 2 - 3 - 4

+

Niveau de zoom (timeline) 1 - 2 - 3 - 4

+
\ No newline at end of file diff -r 7d9c576bfaac -r c28048fb63b4 tweetcast/nodejs/client/js/raphael-min.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tweetcast/nodejs/client/js/raphael-min.js Tue Oct 18 16:19:08 2011 +0200 @@ -0,0 +1,8 @@ +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2.0 - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +(function(a){var b="0.3.2",c="hasOwnProperty",d=/[\.\/]/,e="*",f=function(){},g=function(a,b){return a-b},h,i,j={n:{}},k=function(a,b){var c=j,d=i,e=Array.prototype.slice.call(arguments,2),f=k.listeners(a),l=0,m=!1,n,o=[],p={},q=[],r=[];h=a,i=0;for(var s=0,t=f.length;sf*b.top){e=b.percents[y],p=b.percents[y-1]||0,t=t/b.top*(e-p),o=b.percents[y+1],j=b.anim[e];break}f&&d.attr(b.anim[b.percents[y]])}if(!!j){if(!k){for(attr in j)if(j[g](attr))if(U[g](attr)||d.paper.customAttributes[g](attr)){u[attr]=d.attr(attr),u[attr]==null&&(u[attr]=T[attr]),v[attr]=j[attr];switch(U[attr]){case C:w[attr]=(v[attr]-u[attr])/t;break;case"colour":u[attr]=a.getRGB(u[attr]);var A=a.getRGB(v[attr]);w[attr]={r:(A.r-u[attr].r)/t,g:(A.g-u[attr].g)/t,b:(A.b-u[attr].b)/t};break;case"path":var B=bG(u[attr],v[attr]),D=B[1];u[attr]=B[0],w[attr]=[];for(y=0,z=u[attr].length;yd)return d;while(cf?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cd(){return this.x+q+this.y+q+this.width+" × "+this.height}function cc(){return this.x+q+this.y}function bR(a,b,c,d,e,f){a!=null?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function bw(a){var b=[];for(var c=0,d=a.length;d-2>c;c+=2){var e=[{x:+a[c],y:+a[c+1]},{x:+a[c],y:+a[c+1]},{x:+a[c+2],y:+a[c+3]},{x:+a[c+4],y:+a[c+5]}];d-4==c?(e[0]={x:+a[c-2],y:+a[c-1]},e[3]=e[2]):c&&(e[0]={x:+a[c-2],y:+a[c-1]}),b.push(["C",(-e[0].x+6*e[1].x+e[2].x)/6,(-e[0].y+6*e[1].y+e[2].y)/6,(e[1].x+6*e[2].x-e[3].x)/6,(e[1].y+6*e[2].y-e[3].y)/6,e[2].x,e[2].y])}return b}function bv(){return this.hex}function bt(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),h=d.cache=d.cache||{},i=d.count=d.count||[];if(h[g](f)){bs(i,f);return c?c(h[f]):h[f]}i.length>=1e3&&delete h[i.shift()],i.push(f),h[f]=a[m](b,e);return c?c(h[f]):h[f]}return d}function bs(a,b){for(var c=0,d=a.length;c',bk=bj.firstChild,bk.style.behavior="url(#default#VML)";if(!bk||typeof bk.adj!="object")return a.type=p;bj=null}a.svg=!(a.vml=a.type=="VML"),a._Paper=j,a.fn=k=j.prototype=a.prototype,a._id=0,a._oid=0,a.is=function(a,b){b=v.call(b);if(b=="finite")return!M[g](+a);if(b=="array")return a instanceof Array;return b=="null"&&a===null||b==typeof a&&a!==null||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||H.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return(180+w.atan2(-i,-h)*180/B+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*B/180},a.deg=function(a){return a*180/B%360},a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,E)){var e=b.length;while(e--)if(z(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c};var bl=a.createUUID=function(a,b){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=w.random()*16|0,c=a=="x"?b:b&3|8;return c.toString(16)});a.setWindow=function(b){eve("setWindow",a,h.win,b),h.win=b,h.doc=h.win.document,initWin&&initWin(h.win)};var bm=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),d=e.body}catch(f){d=createPopup().document.body}var g=d.createTextRange();bm=bt(function(a){try{d.style.color=r(a).replace(c,p);var b=g.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b.toString(16)).slice(-6)}catch(e){return"none"}})}else{var i=h.doc.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",h.doc.body.appendChild(i),bm=bt(function(a){i.style.color=a;return h.doc.defaultView.getComputedStyle(i,p).getPropertyValue("color")})}return bm(b)},bn=function(){return"hsb("+[this.h,this.s,this.b]+")"},bo=function(){return"hsl("+[this.h,this.s,this.l]+")"},bp=function(){return this.hex},bq=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,D)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;return[b,c,d]},br=function(b,c,d,e){b*=255,c*=255,d*=255;var f={r:b,g:c,b:d,hex:a.rgb(b,c,d),toString:bp};a.is(e,"finite")&&(f.opacity=e);return f};a.color=function(b){var c;a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b?(c=a.hsb2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b?(c=a.hsl2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):(a.is(b,"string")&&(b=a.getRGB(b)),a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b?(c=a.rgb2hsl(b),b.h=c.h,b.s=c.s,b.l=c.l,c=a.rgb2hsb(b),b.v=c.b):(b={hex:"none"},crl.r=b.g=b.b=b.h=b.s=b.v=b.l=-1)),b.toString=bp;return b},a.hsb2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;a=a%360/60,i=c*b,h=i*(1-z(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return br(e,f,g,d)},a.hsl2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h);if(a>1||b>1||c>1)a/=360,b/=100,c/=100;a*=360;var e,f,g,h,i;a=a%360/60,i=2*b*(c<.5?c:1-c),h=i*(1-z(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return br(e,f,g,d)},a.rgb2hsb=function(a,b,c){c=bq(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;f=x(a,b,c),g=f-y(a,b,c),d=g==0?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=g==0?0:g/f;return{h:d,s:e,b:f,toString:bn}},a.rgb2hsl=function(a,b,c){c=bq(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;g=x(a,b,c),h=y(a,b,c),i=g-h,d=i==0?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=i==0?0:f<.5?i/(2*f):i/(2-2*f);return{h:d,s:e,l:f,toString:bo}},a._path2string=function(){return this.join(",").replace(X,"$1")};var bu=a._preload=function(a,b){var c=h.doc.createElement("img");c.style.cssText="position:absolute;left:-9999em;top-9999em",c.onload=function(){b.call(this),this.onload=null,h.doc.body.removeChild(this)},c.onerror=function(){h.doc.body.removeChild(this)},h.doc.body.appendChild(c),c.src=a};a.getRGB=bt(function(b){if(!b||!!((b=r(b)).indexOf("-")+1))return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bv};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none",toString:bv};!W[g](b.toLowerCase().substring(0,2))&&b.charAt()!="#"&&(b=bm(b));var c,d,e,f,h,i,j,k=b.match(L);if(k){k[2]&&(f=R(k[2].substring(5),16),e=R(k[2].substring(3,5),16),d=R(k[2].substring(1,3),16)),k[3]&&(f=R((i=k[3].charAt(3))+i,16),e=R((i=k[3].charAt(2))+i,16),d=R((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),k[1].toLowerCase().slice(0,4)=="rgba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100));if(k[5]){j=k[5][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,f,h)}if(k[6]){j=k[6][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsla"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,f,h)}k={r:d,g:e,b:f,toString:bv},k.hex="#"+(16777216|f|e<<8|d<<16).toString(16).slice(1),a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bv}},a),a.hsb=bt(function(b,c,d){return a.hsb2rgb(b,c,d).hex}),a.hsl=bt(function(b,c,d){return a.hsl2rgb(b,c,d).hex}),a.rgb=bt(function(a,b,c){return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=bt(function(b){if(!b)return null;var c={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=by(b)),d.length||r(b).replace(Y,function(a,b,e){var f=[],g=b.toLowerCase();e.replace($,function(a,b){b&&f.push(+b)}),g=="m"&&f.length>2&&(d.push([b][n](f.splice(0,2))),g="l",b=b=="m"?"l":"L");if(g=="r")d.push([b][n](f));else while(f.length>=c[g]){d.push([b][n](f.splice(0,c[g])));if(!c[g])break}}),d.toString=a._path2string;return d}),a.parseTransformString=bt(function(b){if(!b)return null;var c={r:3,s:4,t:2,m:6},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=by(b)),d.length||r(b).replace(Z,function(a,b,c){var e=[],f=v.call(b);c.replace($,function(a,b){b&&e.push(+b)}),d.push([b][n](e))}),d.toString=a._path2string;return d}),a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=A(j,3),l=A(j,2),m=i*i,n=m*i,o=k*a+l*3*i*c+j*3*i*i*e+n*g,p=k*b+l*3*i*d+j*3*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,x=j*e+i*g,y=j*f+i*h,z=90-w.atan2(q-s,r-t)*180/B;(q>s||r1&&(v=w.sqrt(v),c=v*c,d=v*d);var x=c*c,y=d*d,A=(f==g?-1:1)*w.sqrt(z((x*y-x*u*u-y*t*t)/(x*u*u+y*t*t))),C=A*c*u/d+(a+h)/2,D=A*-d*t/c+(b+i)/2,E=w.asin(((b-D)/d).toFixed(9)),F=w.asin(((i-D)/d).toFixed(9));E=aF&&(E=E-B*2),!g&&F>E&&(F=F-B*2)}else E=j[0],F=j[1],C=j[2],D=j[3];var G=F-E;if(z(G)>k){var H=F,I=h,J=i;F=E+k*(g&&F>E?1:-1),h=C+c*w.cos(F),i=D+d*w.sin(F),m=bD(h,i,c,d,e,0,g,I,J,[F,H,C,D])}G=F-E;var K=w.cos(E),L=w.sin(E),M=w.cos(F),N=w.sin(F),O=w.tan(G/4),P=4/3*c*O,Q=4/3*d*O,R=[a,b],S=[a+P*L,b-Q*K],T=[h+P*N,i-Q*M],U=[h,i];S[0]=2*R[0]-S[0],S[1]=2*R[1]-S[1];if(j)return[S,T,U][n](m);m=[S,T,U][n](m).join()[s](",");var V=[];for(var W=0,X=m.length;W"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bE(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bE(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,z(l)>"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bE(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bE(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y));return{min:{x:y[m](0,p),y:y[m](0,o)},max:{x:x[m](0,p),y:x[m](0,o)}}}),bG=a._path2curve=bt(function(a,b){var c=bA(a),d=b&&bA(b),e={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][n](bD[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][n](bC(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][n](bC(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](bB(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](bB(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](bB(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](bB(b.x,b.y,b.X,b.Y))}return a},h=function(a,b){if(a[b].length>7){a[b].shift();var e=a[b];while(e.length)a.splice(b++,0,["C"][n](e.splice(0,6)));a.splice(b,1),k=x(c.length,d&&d.length||0)}},i=function(a,b,e,f,g){a&&b&&a[g][0]=="M"&&b[g][0]!="M"&&(b.splice(g,0,["M",f.x,f.y]),e.bx=0,e.by=0,e.x=a[g][1],e.y=a[g][2],k=x(c.length,d&&d.length||0))};for(var j=0,k=x(c.length,d&&d.length||0);j=j)return p;o=p}if(j==null)return k},cg=function(b,c){return function(d,e,f){d=bG(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;oe){if(c&&!l.start){m=cf(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=["C"+m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=["M"+m.x,m.y+"C"+m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cf(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i.shift()+i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},ch=cg(1),ci=cg(),cj=cg(0,1);a.getTotalLength=ch,a.getPointAtLength=ci,a.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return cj(a,b).end;var d=cj(a,c,1);return b?cj(d,b).end:d},b_.getTotalLength=function(){if(this.type=="path"){if(this.node.getTotalLength)return this.node.getTotalLength();return ch(this.attrs.path)}},b_.getPointAtLength=function(a){if(this.type=="path")return ci(this.attrs.path,a)},b_.getSubpath=function(b,c){if(this.type=="path")return a.getSubpath(this.attrs.path,b,c)};var ck=a.easing_formulas={linear:function(a){return a},"<":function(a){return A(a,1.7)},">":function(a){return A(a,.48)},"<>":function(a){var b=.48-a/1.04,c=w.sqrt(.1734+b*b),d=c-b,e=A(z(d),1/3)*(d<0?-1:1),f=-c-b,g=A(z(f),1/3)*(f<0?-1:1),h=e+g+.5;return(1-h)*3*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==!!a)return a;return A(2,-10*a)*w.sin((a-.075)*2*B/.3)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};ck.easeIn=ck["ease-in"]=ck["<"],ck.easeOut=ck["ease-out"]=ck[">"],ck.easeInOut=ck["ease-in-out"]=ck["<>"],ck["back-in"]=ck.backIn,ck["back-out"]=ck.backOut;var cl=[],cm=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,16)},cn=function(){var b=+(new Date),c=0;for(;c1&&!d.next){for(s in k)k[g](s)&&(r[s]=d.totalOrigin[s]);d.el.attr(r),cr(d.anim,d.el,d.anim.percents[0],null,d.totalOrigin,d.repeat-1)}d.next&&!d.stop&&cr(d.anim,d.el,d.next,null,d.totalOrigin,d.repeat)}}a.svg&&m&&m.paper&&m.paper.safari(),cl.length&&cm(cn)},co=function(a){return a>255?255:a<0?0:a};b_.animateWith=function(b,c,d,e,f,g){var h=d?a.animation(d,e,f,g):c;status=b.status(c);return this.animate(h).status(h,status*c.ms/h.ms)},b_.onAnimation=function(a){a?eve.on("anim.frame."+this.id,a):eve.unbind("anim.frame."+this.id);return this},cq.prototype.delay=function(a){var b=new cq(this.anim,this.ms);b.times=this.times,b.del=+a||0;return b},cq.prototype.repeat=function(a){var b=new cq(this.anim,this.ms);b.del=this.del,b.times=w.floor(x(a,0))||1;return b},a.animation=function(b,c,d,e){if(b instanceof cq)return b;if(a.is(d,"function")||!d)e=e||d||null,d=null;b=Object(b),c=+c||0;var f={},h,i;for(i in b)b[g](i)&&Q(i)!=i&&Q(i)+"%"!=i&&(h=!0,f[i]=b[i]);if(!h)return new cq(b,c);d&&(f.easing=d),e&&(f.callback=e);return new cq({100:f},c)},b_.animate=function(b,c,d,e){var f=this;if(f.removed){e&&e.call(f);return f}var g=b instanceof cq?b:a.animation(b,c,d,e);cr(g,f,g.percents[0],null,f.attr());return f},b_.setTime=function(a,b){a&&b!=null&&this.status(a,y(b,a.ms)/a.ms);return this},b_.status=function(a,b){var c=[],d=0,e,f;if(b!=null){cr(a,this,-1,y(b,1));return this}e=cl.length;for(;d.5)*2-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&n!=.5&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\s*\-\s*/);if(j=="linear"){var t=e.shift();t=-d(t);if(isNaN(t))return null;var u=[0,0,f.cos(a.rad(t)),f.sin(a.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=a._parseDots(e);if(!w)return null;b.gradient&&(p.defs.removeChild(b.gradient),delete b.gradient),k=k.replace(/[\(\)\s,\xb0#]/g,"-"),s=q(j+"Gradient",{id:k}),b.gradient=s,q(s,j=="radial"?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:b.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;x1?E.opacity/100:E.opacity});case"stroke":E=a.getRGB(p),i.setAttribute(o,E.hex),o=="stroke"&&E[b]("opacity")&&q(i,{"stroke-opacity":E.opacity>1?E.opacity/100:E.opacity}),o=="stroke"&&d._.arrows&&("startString"in d._.arrows&&w(d,d._.arrows.startString),"endString"in d._.arrows&&w(d,d._.arrows.endString,1));break;case"gradient":(d.type=="circle"||d.type=="ellipse"||c(p).charAt()!="r")&&u(d,p);break;case"opacity":k.gradient&&!k[b]("stroke-opacity")&&q(i,{"stroke-opacity":p>1?p/100:p});case"fill-opacity":if(k.gradient){F=a._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l)),F&&(G=F.getElementsByTagName("stop"),q(G[G.length-1],{"stop-opacity":p}));break};default:o=="font-size"&&(p=e(p,10)+"px");var H=o.replace(/(\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[H]=p,d._.dirty=1,i.setAttribute(o,p)}}B(d,f),i.style.visibility=m},A=1.2,B=function(d,f){if(d.type=="text"&&!!(f[b]("text")||f[b]("font")||f[b]("font-size")||f[b]("x")||f[b]("y"))){var g=d.attrs,h=d.node,i=h.firstChild?e(a._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue("font-size"),10):10;if(f[b]("text")){g.text=f.text;while(h.firstChild)h.removeChild(h.firstChild);var j=c(f.text).split("\n"),k=[],m;for(var n=0,o=j.length;n"));var Y=V.getBoundingClientRect();t.W=m.w=(Y.right-Y.left)/W,t.H=m.h=(Y.bottom-Y.top)/W,t.X=m.x,t.Y=m.y+t.H/2,("x"in i||"y"in i)&&(t.path.v=a.format("m{0},{1}l{2},{1}",f(m.x*u),f(m.y*u),f(m.x*u)+1));var Z=["x","y","text","font","font-family","font-weight","font-style","font-size"];for(var $=0,_=Z.length;$<_;$++)if(Z[$]in i){t._.dirty=1;break}switch(m["text-anchor"]){case"start":t.textpath.style["v-text-align"]="left",t.bbx=t.W/2;break;case"end":t.textpath.style["v-text-align"]="right",t.bbx=-t.W/2;break;default:t.textpath.style["v-text-align"]="center",t.bbx=0}t.textpath.style["v-text-kern"]=!0}},addGradientFill=function(b,f,g){b.attrs=b.attrs||{};var h=b.attrs,i=Math.pow,j,k,l="linear",m=".5 .5";b.attrs.gradient=f,f=c(f).replace(a._radial_gradient,function(a,b,c){l="radial",b&&c&&(b=d(b),c=d(c),i(b-.5,2)+i(c-.5,2)>.25&&(c=e.sqrt(.25-i(b-.5,2))*((c>.5)*2-1)+.5),m=b+n+c);return o}),f=f.split(/\s*\-\s*/);if(l=="linear"){var p=f.shift();p=-d(p);if(isNaN(p))return null}var q=a._parseDots(f);if(!q)return null;b=b.shape||b.node;if(q.length){b.removeChild(g),g.on=!0,g.method="none",g.color=q[0].color,g.color2=q[q.length-1].color;var r=[];for(var s=0,t=q.length;s')}}catch(c){B=function(a){return b.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}};C(a._g.win),a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b.container,d=b.height,e,f=b.width,g=b.x,h=b.y;if(!c)throw new Error("VML container not found.");var i=new a._Paper,j=i.canvas=a._g.doc.createElement("div"),k=j.style;g=g||0,h=h||0,f=f||512,d=d||342,i.width=f,i.height=d,f==+f&&(f+="px"),d==+d&&(d+="px"),i.coordsize=u*1e3+n+u*1e3,i.coordorigin="0 0",i.span=a._g.doc.createElement("span"),i.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",j.appendChild(i.span),k.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d),c==1?(a._g.doc.body.appendChild(j),k.left=g+"px",k.top=h+"px",k.position="absolute"):c.firstChild?c.insertBefore(j,c.firstChild):c.appendChild(j),i.renderfix=function(){};return i},a.prototype.clear=function(){a.eve("clear",this),this.canvas.innerHTML=o,this.span=a._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},a.prototype.remove=function(){a.eve("remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=removed(b);return!0};var D=a.st;for(var E in A)A[b](E)&&!D[b](E)&&(D[E]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(E))}(window.Raphael) \ No newline at end of file diff -r 7d9c576bfaac -r c28048fb63b4 tweetcast/nodejs/client/js/script.js --- a/tweetcast/nodejs/client/js/script.js Mon Oct 17 17:40:58 2011 +0200 +++ b/tweetcast/nodejs/client/js/script.js Tue Oct 18 16:19:08 2011 +0200 @@ -1,10 +1,11 @@ var socket, + paper, tweetData = { "tweetcount" : 0, "position" : -1, "zoomLevel" : 3, "timeLevel" : 2 - } + }, zoomLevels = [ { "description" : "160 tweets per page", @@ -26,7 +27,14 @@ "className" : "full", "displayCount" : 6 } - ]; + ], + colors = { + 'positive' : "#1D973D", + 'reference' : "#C5A62D", + 'negative' : "#CE0A15", + 'question' : "#036AAE" + }, + timeWindow; function tweetToHtml(tweet) { html = '
  • 3 ? .5 : 0), 600 - ((i+1) * scaleY) + (scaleY > 3 ? .5 : 0), scaleX - (scaleX > 3 ? 1 : 0), scaleY - (scaleY > 3 ? 1 : 0)).attr({"stroke":"none","fill":coul}); + } + } + for (var i = 0; i < data.arcs.length; i++) { + var x1 = scaleX * (tmptw[data.arcs[i].from].x + .5), + x2 = scaleX * (tmptw[data.arcs[i].to].x + .5), + y1 = 600 - scaleY * (tmptw[data.arcs[i].from].y + .5), + y2 = 600 - scaleY * (tmptw[data.arcs[i].to].y + .5), + d = "M"+x1+" "+y1+"C"; + if (y1 == y2) { + d += x1+" "+(y1 - 60)+" "+x2+" "+(y2 - 60); + } else { + d += (x1 + 60)+" "+y1+" "+(x2 + 60)+" "+y2; + } + paper.path(d+" "+x2+" "+y2); + } + showTimeWindow(); }); }); \ No newline at end of file diff -r 7d9c576bfaac -r c28048fb63b4 tweetcast/nodejs/server/node-direct.js --- a/tweetcast/nodejs/server/node-direct.js Mon Oct 17 17:40:58 2011 +0200 +++ b/tweetcast/nodejs/server/node-direct.js Tue Oct 18 16:19:08 2011 +0200 @@ -1,13 +1,16 @@ READ_OLD_TWEETS = true; RECORD_NEW_TWEETS = true; -TWEET_FILE_PATH = 'tweets.txt'; -TRACKING_KEYWORD = 'Bieber'; +TWEET_FILE_DIR = './'; +TWEET_FILE_START = 'tweets-'; +TWEET_FILE_EXT = '.txt'; +TRACKING_KEYWORD = '#p2'; var fs = require('fs'), https = require('https'), io = require('socket.io') .listen(8000), tweets = [], + arcs = [], tweet_ids = [], date_struct = [], date_levels = [ @@ -21,9 +24,12 @@ 'negative' : '--', 'reference' : '==', 'question' : '??' - } + }; function populateDateStruct(level, start) { + if (typeof start == "object") { + start = start.valueOf(); + } var end = start + date_levels[level], struct = { "level" : level, @@ -39,7 +45,7 @@ } } else { struct.tweets = []; - struct.annotations = []; + struct.annotations = {}; } return struct; } @@ -52,13 +58,13 @@ insertIntoDateStruct(slices[i].slices, tweet); } else { slices[i].tweets.push(tweet.pos); - for (var j in tweet.annotations) { - if (slices[i].annotations[j]) { - slices[i].annotations[j]++; + if (tweet.annotations.length) { + var ann = tweet.annotations[0]; + if (slices[i].annotations[ann]) { + slices[i].annotations[ann].push(tweet.pos); } else { - slices[i].annotations[j] = 1; + slices[i].annotations[ann] = [ tweet.pos ]; } - break; } } break; @@ -66,6 +72,62 @@ } } +function getSliceContent(slice) { + if (slice.slices) { + var twz = [], + annotations = {}; + for (var i in slice.slices) { + var data = getSliceContent(slice.slices[i]); + twz = twz.concat(data.tweets); + for (var j in data.annotations) { + if (annotations[j]) { + annotations[j] = annotations[j].concat(data.annotations[j]); + } else { + annotations[j] = data.annotations[j]; + } + } + } + } else { + twz = slice.tweets; + annotations = slice.annotations; + } + return { "tweets" : twz, "annotations" : annotations } +}; + +function flattenDateStruct(slices, target_level) { + var current_level = slices[0].level, + result = []; + if (current_level < target_level) { + if (slices[0].slices) { + for (var i in slices) { + result = result.concat(flattenDateStruct(slices[i].slices, target_level)); + } + } + } + else { + for (var i in slices) { + var data = getSliceContent(slices[i]); + result.push({ + "start" : slices[i].start, + "end" : slices[i].end, + "tweets" : data.tweets, + "annotations" : data.annotations + }); + } + } + return result; +} + +function trimFDS(slices) { + while (slices[0].tweets.length == 0) { + slices.splice(0,1); + } + while (slices[slices.length - 1].tweets.length == 0) { + slices.pop(); + } + return slices; +} + function addToList(tweet) { if (tweet_ids.indexOf(tweet.id) != -1) { console.log("Error: Tweet already in list"); @@ -79,9 +141,29 @@ date_struct = [ populateDateStruct(0, date_levels[0] * parseInt(creadate / date_levels[0])) ] } while (creadate > date_struct[date_struct.length - 1].end) { - date_struct.push( populateDateStruct(0, date_struct[date_struct.length - 1].end) ); + date_struct.push( populateDateStruct(0, date_struct[date_struct.length - 1].end.valueOf()) ); } insertIntoDateStruct(date_struct, tweet); + if (tweet.in_reply_to_status_id) { + var ref = tweet_ids.indexOf(tweet.in_reply_to_status_id) + if (ref != -1) { + arcs.push({ + "from" : tweet.pos, + "to" : ref, + "type" : "reply" + }); + } + } + if (tweet.retweeted_status) { + var ref = tweet_ids.indexOf(tweet.retweeted_status.id_str) + if (ref != -1) { + arcs.push({ + "from" : tweet.pos, + "to" : ref, + "type" : "retweet" + }); + } + } } function textids(object) { @@ -93,33 +175,61 @@ } } -if (READ_OLD_TWEETS) { - try { - var filebuff = ""; - readstream = fs.createReadStream(TWEET_FILE_PATH, { flags: 'r', encoding: 'utf-8' }); - readstream.on("data", function(data) { - console.log("data"); - filebuff += data; - }); - readstream.on("end", function() { - console.log("end"); - oldtweets = filebuff.split('\r\n'); - var tweetscopied = 0; - for (var i in oldtweets) { - if (oldtweets[i].length > 0) { - addToList(JSON.parse(oldtweets[i])); +function readTweetsFromFile() { + var dir = fs.readdirSync(TWEET_FILE_DIR), + fileName = null; + for (var i in dir) { + if ( dir[i].indexOf( TWEET_FILE_START + encodeURIComponent(TRACKING_KEYWORD) ) == 0 ) { + var oldtweets = fs.readFileSync(dir[i], 'utf8').split('\n'), + tweetscopied = 0; + for (var j in oldtweets) { + if (oldtweets[j].length > 1) { + addToList(JSON.parse(oldtweets[j])); tweetscopied++; } } - console.log(tweetscopied, "tweets copied from", TWEET_FILE_PATH); - }); - } catch(err) { - console.log(err); + console.log(tweetscopied, "tweets copied from", dir[i]); + console.log(arcs); + } } } +function callBackNewTweets(chunk) { + var newdata = chunk.split('\r\n'); + for (var i in newdata) { + if (newdata[i].length > 0) { + var tweet = JSON.parse(newdata[i]), + annotations = []; + for (var a in annkw) { + if (tweet.text.indexOf(annkw[a]) != -1) { + annotations.push(a); + } + } + tweet.annotations = annotations; + textids(tweet); + textids(tweet.user); + + addToList(tweet); + var txt = JSON.stringify(tweet)+'\n'; + writestream.write(txt); + } + } + console.log("New tweets received. We now have", tweets.length, "tweets in memory"); + io.sockets.emit('tweetSummary', { tweetcount : tweets.length }); +} + +/* MAIN CODE */ + +if (READ_OLD_TWEETS) { + readTweetsFromFile(); +} + if (RECORD_NEW_TWEETS) { - var writestream = null; + var now = new Date(), + fileTimestamp = (1900+now.getYear())+"-"+("0"+(1+now.getMonth())).slice(-2)+"-"+("0"+now.getDate()).slice(-2)+"."+("0"+now.getHours()).slice(-2)+"-"+("0"+now.getMinutes()).slice(-2), + fileName = TWEET_FILE_DIR + TWEET_FILE_START + encodeURIComponent(TRACKING_KEYWORD) + '-' + fileTimestamp + TWEET_FILE_EXT, + writestream = fs.createWriteStream(fileName, { flags: 'w', encoding: 'utf-8' }); + console.log('Writing to',fileName); var req = https.request({ host: "stream.twitter.com", path: "/1/statuses/filter.json", @@ -132,34 +242,7 @@ console.log('STATUS: ' + res.statusCode); console.log('HEADERS: ' + JSON.stringify(res.headers)); res.setEncoding('utf8'); - res.on('data', function(chunk) { - var newdata = chunk.split('\r\n'); - try { - for (var i in newdata) { - if (newdata[i].length > 0) { - var tweet = JSON.parse(newdata[i]), - annotations = []; - for (var a in annkw) { - if (tweet.text.indexOf(annkw[a]) != -1) { - annotations.push(a); - } - } - tweet.annotations = annotations; - textids(tweet); - addToList(tweet); - } - } - if (!writestream) { - writestream = fs.createWriteStream(TWEET_FILE_PATH, { flags: 'a', encoding: 'utf-8' }); - } - writestream.write(chunk); - io.sockets.emit('tweetSummary', { tweetcount : tweets.length }); - console.log("New tweets received. We now have", tweets.length, "tweets in memory"); - } - catch(err) { - console.log(err); - } - }); + res.on('data', callBackNewTweets); }); req.write('track=' + encodeURIComponent(TRACKING_KEYWORD)); @@ -168,9 +251,15 @@ io.set('log level', 0); io.sockets.on('connection', function(socket) { - console.log("New connection", socket); + console.log("New connection from", socket.handshake.address.address,"id :", socket.id); socket.emit('tweetSummary', { tweetcount : tweets.length }); socket.on('getTweets', function(data) { - socket.emit('tweets', tweets.slice(Math.max(0, data.from), data.to)); + console.log('getTweets from',socket.id); + data.tweets = tweets.slice(Math.max(0, data.from), data.to); + socket.emit('tweets', data); + }); + socket.on('getTimeline', function(data) { + socket.emit('timeline', { "timeline" : trimFDS(flattenDateStruct(date_struct, data.level)), "arcs" : arcs }); + console.log('getTimeline from',socket.id); }); }); \ No newline at end of file