// options var options = {}; options.mode = 'direct'; // old options.URL_BASE_DIRECT = 'http://search.twitter.com/search.json'; // TOOD gérer autho et passer à 1.1 ! //var options.URL_BASE_DIRECT = 'https://api.twitter.com/1.1/search/tweets.json'; options.URL_BASE_INDIRECT = 'https://appartsam.thiriot.net/twitterbattle/relay.php'; options.option_display_last=true; options.option_filter_withdataonly=false; // very coslty options.option_show_images=true; options.option_preload_images=false; options.option_preload_avatars=false; options.option_show_random_birds=true; // max total node displayed in the space options.maxnodes = 600; // delay for refresh (s) options.delay = 10000; // delay for update after errors options.delayRetryError = 1500; // if true, use canvas instead of SVG options.useCanvas = true; options.color1 = "brown"; options.color2 = "gray"; options.colorDefault = "#DDD"; options.timeoutGetTweets = 2000; var DEBUG = false; // internal state of the IHM var state = {}; var guiElements = {}; // state for auto display of tweets state.stateTweetsAutoDisplay = {}; // timestamp ou le dernier tweet a été affiché state.stateTweetsAutoDisplay.timestamp_lasttweet_displayed=undefined; var dateServer = new Date("2025/12/06 04:52:33 +0100"); var dateLocal = new Date(); var diffHour = dateServer - dateLocal; // true if everything is init state.isInitialLoad = true; guiElements.svg = undefined; guiElements.canvas = undefined; function displayMessageNotCompliant() { $('div#backgroundpb').stop().fadeTo(1000,0.2).fadeTo(5000,0.7); $('#msgslot').html('
Sorry, your browser is too old for this experience. Please consider updating your browser or installing a more recent browser, for instance:
Mozilla FirefoxGoogle ChromeApple SafariOperaMicrosoft Internet Explorer
'); } // first detections if (!Modernizr.canvas || !Modernizr.canvastext) { displayMessageNotCompliant(); } if (options.useCanvas) { guiElements.canvas = d3 .select("#divanim").append("canvas") .text(':-(') .attr("width", window.innerWidth+"px") .attr("height", window.innerHeight+"px") .attr("id", "canvasanim"); guiElements.canvasObj = document.getElementById("canvasanim"); if (guiElements.canvasObj == null) { displayMessageNotCompliant(); } state.nodeDragged = undefined; state.nodeselected = undefined; state.nodeselectedtmp = undefined; state.nodeselectedAuto = undefined; guiElements.canvasObj.onmousedown = function(e) { if (state.nodeselected != undefined) { state.nodeselected.selected = false; state.nodeselected = undefined; } if (state.nodeselectedAuto != undefined) { state.nodeselectedAuto.selected = false; state.nodeselectedAuto = undefined; } state.nodeselectedtmp = undefined; var node = find(e.clientX, e.clientY); if (node !== undefined) { state.nodeDragged = node; //state.force.stop(); state.nodeDragged.fixed = 2; // = true node.selected = true; state.nodeselected = node; state.nodeselectedtmp = node; displayTweet(node.data); } } guiElements.canvasObj.onmouseup = function(e) { if (state.nodeDragged) { state.nodeDragged.fixed = 0; // = false state.nodeDragged = undefined; state.force.resume(); } } var tweetDisplayed = undefined; guiElements.canvasObj.onmousemove = function(e) { if (state.nodeDragged !== undefined) { // we are moving somthing ! state.nodeDragged.x = e.clientX; state.nodeDragged.y = e.clientY; state.nodeDragged.px = e.clientX; state.nodeDragged.py = e.clientY; state.force.resume(); } else { if (state.nodeselected == undefined) { // don't care when we already know what to display ! var n = find(e.clientX, e.clientY); if (n !== undefined) { // found something if (tweetDisplayed != n.data) { displayTweet(n.data); state.nodeselectedtmp = n; tweetDisplayed = n.data; } } else { if (tweetDisplayed !== undefined) { noMoreTweetDisplayed(); //somethingDisplayed = false; }; } } } } } else { guiElements.svg = d3 .select("#divanim").append("guiElements.svg") .attr("width", "100%") .attr("height", "100%") .attr("id", "guiElements.svganim"); } //var msg = d3.select("#messages"); var tweetdisplay = {}; tweetdisplay.container = $('div#tweetdiv'); tweetdisplay.container.hide(); tweetdisplay.content = $('div#tweetcontent'); tweetdisplay.authoravatar = document.getElementById("tweetauthoravatar"); tweetdisplay.authorlinks = $('a.tweetlkuser'); tweetdisplay.authorname = $('a#tweetauthornamelk'); tweetdisplay.authorusername = $('a#tweetauthorusernamelk'); tweetdisplay.timestamp= $('div#tweettimestamp'); tweetdisplay.actions= $('div#tweetactions'); tweetdisplay.actionReplyLink = $('a#tweetlkreply'); tweetdisplay.actionRetweetLink = $('a#tweetlkretweet'); tweetdisplay.actionFavoriteLink = $('a#tweetlkfavorite'); //tweetdisplay.actionFollow = $('a#tweetlkfollow'); tweetdisplay.actionFollow = $('#tweetiffollow'); tweetdisplay.mediacontainer = $('div#tweetmedia'); tweetdisplay.birdimg = $('#birdimg'); guiElements.formparams = document.getElementById("guiElements.formparams"); state.rationodesize = window.innerHeight/72; //var textdefault = "What does twitter cares about ?"; // init state for nodes nodes = []; state.id2node = {}; //state.links = []; state.force = d3.layout.force() //.state.links(state.links) // .gravity(0.9) // .charge(-40) .gravity(0.02) .charge(-2) // -2 .nodes(nodes) // .linkDistance(0.1) // .state.linkstrength(0.1) .size([window.innerWidth, window.innerHeight]) //.drag() .start(); function collide(node) { var r = node.radius +8, nx1 = node.x - r, nx2 = node.x + r, ny1 = node.y - r, ny2 = node.y + r; return function(quad, x1, y1, x2, y2) { if (quad.point && (quad.point !== node)) { var x = node.x - quad.point.x, y = node.y - quad.point.y, l = Math.sqrt(x * x + y * y), r = node.radius + quad.point.radius+4; if (l < r) { l = (l - r) / l * .5; node.x -= x *= l; node.y -= y *= l; quad.point.x += x; quad.point.y += y; } } return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; }; } var COLOR_SELECTED = "red"; var selectionPatternBegin = 0; if (options.useCanvas) { var context = guiElements.canvas.node().getContext("2d"); var pim2 = 2*Math.PI; d3.timer(function() { context.clearRect(0, 0, context.canvas.width, context.canvas.height); context.lineWidth=3; nodes.forEach(function(d) { context.fillStyle = d.color; context.beginPath(); context.arc(d.x, d.y, d.radius, 0, pim2); // TODO manage the case with two colors. /*if (d.selected) { context.stroke(); }*/ context.fill(); if (d.selected) { if (d.color == options.color1) { context.strokeStyle=options.color2; } else { context.strokeStyle=options.color1 }; var totalStep = 14; var step = pim2/totalStep; var currentBegin = selectionPatternBegin; for (i=0; i= x || y1 >= y || x2 < x || y2 < y; }); return thepoint[0]; } // will store the last quadtree ! var q = undefined; state.force.on("tick", function() { var i = 0, n = nodes.length; q = d3.geom.quadtree(nodes); // collisions while (++i < n) { q.visit(collide(nodes[i])); } /* guiElements.svg.selectAll("line.link") .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); */ // update attributes if (!options.useCanvas) { guiElements.svg.selectAll(".node") .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); } }); function clear() { noMoreTweetDisplayed(); nodes.length=0; //state.links.length=0; state.id2node = {}; if (!options.useCanvas) { guiElements.svg.selectAll("circle").remove(); } state.stateTweetsAutoDisplay.timestamp_lasttweet_displayed = undefined; state.nodeselected = undefined; state.nodeselectedAuto = undefined; } function restart() { state.force.stop(); if (!options.useCanvas) { /* guiElements.svg.selectAll("line.link") .data(state.links) .enter().insert("guiElements.svg:line", "circle.node") .attr("class", "link") .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); */ var node = guiElements.svg.selectAll(".node") .data(nodes); node .enter() .append("circle") .attr("class", "node") .attr("id", function(d) { return "A"+d.name; }) .style("fill", function(d) { return d.color; }) .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }) .attr("r", function(d) { return d.radius; }) .on("mouseover", function(d,i) { displayTweet(d.data); }) .on("mouseout", function(d,i) { noMoreTweetDisplayed(); }) .call(state.force.drag); // node.exit().remove(); } state.force.start(); } function noMoreTweetDisplayed() { tweetdisplay.container.stop().fadeOut(900); if (state.nodeselected != undefined) { state.nodeselected.selected = false; state.nodeselected = undefined; } if (state.nodeselectedAuto != undefined) { state.nodeselectedAuto.selected = false; state.nodeselectedAuto = undefined; } state.nodeselectedtmp = undefined; } var monthNames = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); function toTwitterDate(time){ var date = new Date(time), diff = (((new Date()).getTime() - date.getTime()) / 1000), day_diff = Math.floor(diff / 86400); if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 ) return; return day_diff == 0 && ( diff < 10 && "just now" || diff < 60 && Math.floor(diff)+"s" || diff < 3600 && Math.floor( diff / 60 ) + "m" || diff < 86400 && Math.floor( diff / 3600 ) + "h") || day_diff <= 365 && date.getDay()+" "+monthNames[date.getMonth()] || date.getDay()+" "+monthNames[date.getMonth()]+" "+date.getYear(); } function escapeHTML(text) { return $("
").text(text).html(); } // https://gist.github.com/442463 function linkify_entities(tweet) { if (!(tweet.entities)) { return escapeHTML(tweet.text) } // This is very naive, should find a better way to parse this var index_map = {} $.each(tweet.entities.urls, function(i,entry) { index_map[entry.indices[0]] = [entry.indices[1], function(text) {return ""+escapeHTML(entry.display_url)+""}] }) $.each(tweet.entities.hashtags, function(i,entry) { index_map[entry.indices[0]] = [entry.indices[1], function(text) {return ""+escapeHTML(text)+""}] }) $.each(tweet.entities.user_mentions, function(i,entry) { index_map[entry.indices[0]] = [entry.indices[1], function(text) {return ""+escapeHTML(text)+""}] }) if (tweet.entities.media !== undefined) { $.each(tweet.entities.media, function(i,entry) { index_map[entry.indices[0]] = [entry.indices[1], function(text) {return ""+escapeHTML(entry.display_url)+""}] }) } var result = "" var last_i = 0 var i = 0 // iterate through the string looking for matches in the index_map for (i=0; i < tweet.text.length; ++i) { var ind = index_map[i] if (ind) { var end = ind[0] var func = ind[1] if (i > last_i) { result += escapeHTML(tweet.text.substring(last_i, i)) } result += func(tweet.text.substring(i, end)) i = end - 1 last_i = end } } if (i > last_i) { result += escapeHTML(tweet.text.substring(last_i, i)) } return result } var birdsPossible = { 'randomBird1':120, 'randomBird2':65, 'randomBird3':100, 'randomBird4':78, 'randomBird5':97, 'randomBird6':103, 'randomBird7':120, 'randomBird8':100, 'randomBird9':100, 'randomBird10':110, 'randomBird11':110, '_max':10 }; function drawRandomBird() { if (Math.random() <= 0.95) { tweetdisplay.birdimg.hide(); return; } // return positionnodesPossible.verycentercolor; var idx = Math.round(Math.random()*(birdsPossible._max)); var i = 0; for (var key in birdsPossible) { if (i==idx) { tweetdisplay.birdimg.attr("src", "img/"+key).css("top","-"+birdsPossible[key]+"px"); tweetdisplay.birdimg.show(); return; } i++; } if (DEBUG) {console.log("?????");} return undefined; } function displayTweet(data) { if (DEBUG > 1) { console.log("displaying tweet: "); console.log(data); } var pattern, txt=linkify_entities(data); // color our tags for(var i in state.tag2color) { pattern = new RegExp("("+i+")", 'gi'); txt = txt.replace(pattern,'$1'); } // msg.html(data.from_user_name+": "+txt+" ("+data.created_at+")"); var mediacontainercontent = ""; if (options.option_show_images && (data.entities.media != undefined)) { $.each(data.entities.media, function(i,entry) { if (entry.type == "photo") { var size = undefined; if (entry.sizes.thumb != undefined) { size = "thumb"; } else if (entry.sizes.small != undefined) { size = "small"; } else if (entry.sizes.orig != undefined) { size = "orig"; } else if (entry.sizes.large != undefined) { size = "large"; } if (size != "thumb") console.log("size: "+size); if (size != undefined) mediacontainercontent+= ""; } }); } // TOTO tweetdisplay.content.html(txt); tweetdisplay.authoravatar.src = "img/twitter-egg.jpg"; // first call; so if we are unable to load the true one, this will be obious tweetdisplay.authoravatar.src = data.profile_image_url; tweetdisplay.authorlinks.attr("href", "https://twitter.com/intent/user?user_id="+data.from_user_id_str); tweetdisplay.authorname.html(data.from_user_name); tweetdisplay.authorusername.html("@"+data.from_user); tweetdisplay.timestamp.html(""+toTwitterDate(data.created_at)+""); tweetdisplay.actionReplyLink.attr("href", "https://twitter.com/intent/tweet?in_reply_to="+data.id_str); tweetdisplay.actionRetweetLink.attr("href", "https://twitter.com/intent/retweet?tweet_id="+data.id_str); tweetdisplay.actionFavoriteLink.attr("href", "https://twitter.com/intent/favorite?tweet_id="+data.id_str); //tweetdisplay.actionFollow.attr("href", "https://twitter.com/"+data.from_user_name); // twttr.widgets.load(); tweetdisplay.actionFollow.attr("src", "//platform.twitter.com/widgets/follow_button.html?show_count=false&lang=en&show_screen_name=false&screen_name="+data.from_user); tweetdisplay.mediacontainer.html(mediacontainercontent); //tweetdisplay.birdimg.attr("src", "img/randomBird1.png").css("top","-50px"); if (options.option_show_random_birds) { drawRandomBird(); } showTweetDisplay(); // TOTO // $('#messages').stop().fadeTo(100,1.0); } function showTweetDisplay() { tweetdisplay.container.stop().fadeTo(100,1.0); } var positionnodesPossible = { 'randomp':0, 'verycenter':1, 'lineh':2, 'linexy':3, 'lineyx':4, 'bottom':5, 'bottomAndRight':6, 'right':7, 'left':8, 'circle':9, 'colorsBottom':10, 'colorsDiag':11, 'circleColor':12, 'circleoptionsColor2':13, 'linexyColor':14, 'linehColor':15, 'lineyxColor':16, 'bottomColor':17, 'verycentercolor':18, '_max':18 }; //Object.freeze(positionnodesPossible); function getRandomNodesPosition() { // return positionnodesPossible.verycentercolor; var idx = Math.round(Math.random()*(positionnodesPossible._max)); var i = 0; for (var key in positionnodesPossible) { if (i==idx) { return positionnodesPossible[key]; } i++; } if (DEBUG) {console.log("?????");} return undefined; } var positionnodes = positionnodesPossible.randomp; /** * preload images **/ function preload(imgSrc) { if (DEBUG==2) { console.log("preloading: "+imgSrc); } (new Image()).src = imgSrc; } function addNode(i, withdata) { var nodecolor = computeNodeColor(withdata); var xinit,yinit; var rand = Math.random(); var rand2 = Math.random(); switch(positionnodes) { // select node position according to main position scheme case positionnodesPossible.verycenter: xinit = Math.floor((window.innerWidth)/2+(rand-0.5)*30); yinit = Math.floor((window.innerHeight)/2+(rand2-0.5)*30); break; case positionnodesPossible.verycentercolor: if (nodecolor == options.color1) { xinit = Math.floor((window.innerWidth)/2+20+(rand)*15); yinit = Math.floor((window.innerHeight)/2+20+(rand2)*15); } else if (nodecolor == options.color2) { xinit = Math.floor((window.innerWidth)/2-20-(rand)*15); yinit = Math.floor((window.innerHeight)/2-20-(rand2)*15); } else { xinit = Math.floor((window.innerWidth)/2+(rand-0.5)*30); yinit = Math.floor((window.innerHeight)/2+(rand2-0.5)*30); } break; case positionnodesPossible.lineh: xinit = Math.floor(rand*(window.innerWidth)); yinit = Math.floor((window.innerHeight)/2+(rand2-0.5)*5); break; case positionnodesPossible.linehColor: xinit = Math.floor(rand*(window.innerWidth/2)); yinit = Math.floor((window.innerHeight)/2+(rand2-0.5)*5); if (nodecolor == options.color1) { } else if (nodecolor == options.color2) { xinit = xinit+window.innerWidth/2; } else { xinit = xinit+window.innerWidth/4; } break; case positionnodesPossible.linexy: xinit = Math.floor(rand*(window.innerWidth)+(rand2-0.5)*5); yinit = Math.floor(rand*(window.innerHeight)+(rand2-0.5)*5); break; case positionnodesPossible.linexyColor: if (nodecolor == options.color1) { rand = rand / 2; } else if (nodecolor == options.color2) { rand = 0.5 + rand/2; } xinit = Math.floor(rand*(window.innerWidth/2)+(rand2-0.5)*5); yinit = Math.floor(rand*(window.innerHeight/2)+(rand2-0.5)*5); break; case positionnodesPossible.lineyx: xinit = Math.floor(rand*(window.innerWidth)+(rand2-0.5)*5); yinit = Math.floor((1-rand)*(window.innerHeight)+(rand2-0.5)*5); break; case positionnodesPossible.lineyxColor: if (nodecolor == options.color1) { rand = rand/2; } else if (nodecolor == options.color2) { rand = rand/2+0.5; } xinit = Math.floor(rand*(window.innerWidth)+(rand2-0.5)*5); yinit = Math.floor((1-rand)*(window.innerHeight)+(rand2-0.5)*5); break; case positionnodesPossible.bottom: xinit = Math.floor(rand*(window.innerWidth)); yinit = Math.floor(window.innerHeight*0.8+(rand2-0.5)*5); break; case positionnodesPossible.bottomColor: if (nodecolor == options.color1) { rand = rand/2; } else if (nodecolor == options.color2) { rand = rand/2+0.5; } xinit = Math.floor(rand*(window.innerWidth)); yinit = Math.floor(window.innerHeight*0.8+(rand2-0.5)*5); break; case positionnodesPossible.bottombottomAndRight: if (Math.random() <= 0.5) { xinit = Math.floor(rand*(window.innerWidth)); yinit = Math.floor(window.innerHeight*0.8+(rand2-0.5)*5); } else { xinit = Math.floor(0.8*(window.innerWidth)+(rand2-0.5)*5); yinit = Math.floor(rand*window.innerHeight); } break; case positionnodesPossible.right: xinit = Math.floor(0.8*(window.innerWidth)+(rand2-0.5)*5); yinit = Math.floor(rand*window.innerHeight); break; case positionnodesPossible.left: xinit = Math.floor(0.15*(window.innerWidth)+(rand2-0.5)*5); yinit = Math.floor(rand*window.innerHeight); break; case positionnodesPossible.circle: var radius = window.innerHeight/3 + (rand2-0.5)*5; var angle = rand*Math.PI*2; xinit = Math.floor(Math.cos(angle)*radius + window.innerWidth/2); yinit = Math.floor(Math.sin(angle)*radius + window.innerHeight/2); break; case positionnodesPossible.circleColor: var radius; var angle = rand*Math.PI*2; if (nodecolor == options.color2) { radius = window.innerHeight/5 + (rand2-0.5)*5; } else if (nodecolor == options.color1) { radius = window.innerHeight/2 + (rand2-0.5)*5; } else { radius = window.innerHeight/4 + (rand2-0.5)*5; } xinit = Math.floor(Math.cos(angle)*radius + window.innerWidth/2); yinit = Math.floor(Math.sin(angle)*radius + window.innerHeight/2); break; case positionnodesPossible.circlecolor2: var radius = window.innerHeight/2 + (rand2-0.5)*5; var angle; if (nodecolor == options.color1) { angle = Math.PI*2/3+rand*Math.PI; } else if (nodecolor == options.color2) { angle = Math.PI*2/3-rand*Math.PI; } else { angle = rand*Math.PI*2; } xinit = Math.floor(Math.cos(angle)*radius + window.innerWidth/2); yinit = Math.floor(Math.sin(angle)*radius + window.innerHeight/2); break; case positionnodesPossible.colorsBottom: if (nodecolor == options.color1) { xinit = Math.floor(window.innerWidth/4+(rand-0.5)*20); } else if (nodecolor == options.color2) { xinit = Math.floor(window.innerWidth*3/4+(rand-0.5)*20); } else { xinit = Math.floor(window.innerWidth/2+(rand-0.5)*20); } yinit = Math.floor(window.innerHeight*3/4+(rand2-0.5)*5); break; case positionnodesPossible.colorsDiag: if (nodecolor == options.color1) { xinit = Math.floor(window.innerWidth/4+(rand-0.5)*20); yinit = Math.floor(window.innerHeight*3/4+(rand2-0.5)*5); } else if (nodecolor == options.color2) { xinit = Math.floor(window.innerWidth*3/4+(rand-0.5)*20); yinit = Math.floor(window.innerHeight/4+(rand2-0.5)*5); } else { xinit = Math.floor(window.innerWidth/2+(rand-0.5)*20); yinit = Math.floor(window.innerHeight/2+(rand2-0.5)*5); } break; case positionnodesPossible.randomp: default: var random3 = Math.random(); var random4 = Math.random(); if (random3 <= 0.5) { xinit = (random4 <= 0.5 ? Math.floor(rand*(window.innerWidth/3)) : Math.floor((rand+2)*(window.innerWidth/3))); yinit = Math.floor(rand2*window.innerHeight); } else { xinit = Math.floor(rand*window.innerWidth); yinit = (random4 <= 0.3 ? Math.floor(rand2*(window.innerHeight/4)) : Math.floor((rand2+3)*(window.innerHeight/4))); } break; } // console.log("x:"+xinit+",y:"+yinit); // remove node(s) if required if (nodes.length > options.maxnodes) { removeNodes(nodes.length-options.maxnodes); } // add the node var novelNode = nodes.push({x: xinit, y: yinit, name:i, data: withdata, radius: computeNodeRadius(withdata), color:nodecolor }); var thenode = nodes[novelNode-1]; state.id2node[''+i]=thenode; restart(); // display ? if (options.option_display_last && (state.nodeselected == undefined) && (state.nodeselectedtmp == undefined) && (state.stateTweetsAutoDisplay.timestamp_lasttweet_displayed == undefined || (Date.now() - state.stateTweetsAutoDisplay.timestamp_lasttweet_displayed) > 2500)) { state.stateTweetsAutoDisplay.timestamp_lasttweet_displayed = Date.now(); if (state.nodeselectedAuto !== undefined) { state.nodeselectedAuto.selected = false; } displayTweet(withdata); thenode.selected = true; state.nodeselectedAuto = thenode; } // preload data if (options.option_preload_avatars) { preload(withdata.profile_image_url); }; if (options.option_preload_images && withdata.entities.media != undefined) { $.each(withdata.entities.media, function(i,entry) { var size = undefined; if (entry.sizes.thumb != undefined) { size = "thumb"; } else if (entry.sizes.small != undefined) { size = "small"; } else if (entry.sizes.orig != undefined) { size = "orig" }; if (size != undefined) preload(entry.media_url+":"+size); }); } } function computeNodeRadius(withdata) { return Math.round(Math.min(state.rationodesize,(4+withdata.text.length/(state.rationodesize+1)))); } function computeNodeColor(withdata) { var len = 0; // TODO allow mixed colors (with stroke) // try to determine the fill color from hashtags if (withdata.entities.hashtags !== undefined) { len = withdata.entities.hashtags.length; for(var i=0; i 0) { state.tag2color[content.toLowerCase()] = color; } } function changedParamsManu() { // mmm, unselect the preset, thanks $("#preset").val([]); changedParams(); } function changedParams() { // cancel previous tweet updates stopLoadUpdate(); state.isInitialLoad = true; // update the map of tag / color state.tag2color = {}; maybeLoad("aA",options.color1); maybeLoad("aB",options.color1); maybeLoad("aC",options.color1); maybeLoad("bA",options.color2); maybeLoad("bB",options.color2); maybeLoad("bC",options.color2); // update the "searched" part of the url searched = ''; state.currentUrlLink = ''; state.currentUrlLinkLeft = ''; state.currentUrlLinkRight = ''; for(var i in state.tag2color) { if (searched.length > 0) { searched = searched + " OR "; } if (i.indexOf(" ")!=-1) { // if space, enclose into quotes searched = searched + "\"" + i + "\""; } else { searched = searched + i; } if (state.tag2color[i]==options.color1) { if (state.currentUrlLinkLeft.length > 0) { state.currentUrlLinkLeft = state.currentUrlLinkLeft + ","; } state.currentUrlLinkLeft = state.currentUrlLinkLeft + i; } else { if (state.currentUrlLinkRight.length > 0) { state.currentUrlLinkRight = state.currentUrlLinkRight + ","; } state.currentUrlLinkRight = state.currentUrlLinkRight + i; } } state.currentUrlLink = window.location.protocol+"//"+window.location.host+window.location.pathname+"?query="+encodeURIComponent(state.currentUrlLinkLeft + "/" + state.currentUrlLinkRight); // TODO update ! // addthis_share["url"] = state.currentUrlLink; if (addthis !== undefined) { // if the script is not loaded, still continue our work addthis.update('share','url', state.currentUrlLink); } searched = encodeURIComponent(searched); lastRetrieved = 1; // clear the current image which is no more relevant clear(); restart(); // restart the update of tweets updateTweets(); } var retrieved; /* function displayMessage(idmessage) { var msg = ''; switch (idmessage) { case 'loading': msg = "contacting the twitter server..."; break; case 'indirect': msg = "Twitter is not accessible from your network, attempting to contact our relay..."; break; case 'full': msg = "Your screen is full, update stopped."; break; case 'noupdate': msg = "Waiting for server info..."; break; default: return; break; } $('#msgcentral').stop().html(msg).show(); //fadeTo(2000,0.8) } */ function clearMessage() { $('#msgcentral').stop().hide().html(""); } function presedChoosed() { loadFromShort(guiElements.formparams.elements["preset"].value); } function randompreset() { var oldvalue = guiElements.formparams.elements["preset"].value; while (guiElements.formparams.elements["preset"].value == oldvalue) { // avoid to randomly select the same option guiElements.formparams.elements["preset"].options[Math.floor(guiElements.formparams.elements["preset"].options.length*Math.random())].selected = "1"; } presedChoosed(); } function loadFromShort(txt) { var one = txt.split("/"); if (one.length != 2) { return; // error ! } var as = one[0].split(","); var bs = one[1].split(","); guiElements.formparams.elements["aA"].value = (as[0] === undefined ? "": as[0]); guiElements.formparams.elements["aB"].value = (as[1] === undefined ? "": as[1]); guiElements.formparams.elements["aC"].value = (as[2] === undefined ? "": as[2]); guiElements.formparams.elements["bA"].value = (bs[0] === undefined ? "": bs[0]); guiElements.formparams.elements["bB"].value = (bs[1] === undefined ? "": bs[1]); guiElements.formparams.elements["bC"].value = (bs[2] === undefined ? "": bs[2]); changedParams(); } function planTweeterUpdate(delay) { if (updateHolder !== undefined) { clearTimeout(updateHolder); } if (DEBUG) { console.log("planning next tweeter update for "+delay); } updateHolder = setTimeout('updateTweets()', delay); } function filterDisplayResult(item) { var len = 0; // basic filter: remove the tweets with too many hashtags (that's a kind of spam) if (item.entities.hashtags !== undefined) { len1 = item.entities.hashtags.length; if (len1 >= 7) { return false; } len += len1; } // basic filter: remove the tweets with too many user mentions if (item.entities.user_mentions !== undefined) { len2 = item.entities.user_mentions.length; if (len2 >= 5) { return false; } len += len2; } // total filter: too many references = spam if (len >= 8) { return false; } // color: if we are unable to color them, hide them if (computeNodeColor(item) === options.colorDefault) { return false; } return true; } function hideUpdate() { $("#wait").hide(); } var lastRetrievedNext; function processResults(data) { if (data == null || data.error !== undefined) { if (DEBUG) { console.log("error detected: "+(data != null ? data.error:"(unknown)")+"; will try to refresh"); } planTweeterUpdate(options.delayRetryError); displayMessage('noupdate'); return; } //clearMessage(); hideUpdate(); retrieved = data; lastRetrievedNext = data.max_id_str; var date, diff, tmpholderl var now = (new Date()).getTime(); // first nodes added using one random method positionnodes = getRandomNodesPosition(); $.each(data.results, function (i, item) { // filter spams if (!filterDisplayResult(item)) { return; } if (options.option_filter_withdataonly) { if (item.entities.media == undefined || item.entities.media.length == 0) return; } date = (new Date(item.created_at)).getTime(); diff = (date - diffHour - now + options.delay + 20000); if (DEBUG>1) { console.log("diffHour:"+diffHour+",date:"+date+",now:"+now+"; "+diff); } if (diff < 50) { // mmm... too old, display it right now addNodeIfNecessary(item.id, item); } else { // this is a recent tweet; replay how it appears ! if (DEBUG>1) { console.log("options.delayed by "+diff); }; var diff2 = diff; tmpholder = setTimeout(function () { if (DEBUG>1) { console.log("display after waiting "+diff2);} addNodeIfNecessary(item.id, item); }, diff+Math.floor(500*Math.random()) ); holders.push(tmpholder); } }); // later the nodes (not displayed now, but planned) will be added from random positions positionnodes = positionnodesPossible.randomp; if ((data.next_page !== undefined) && ( !state.isInitialLoad || (nodes.length == 0) ) ) { // all the nodes will be displayed later ! // attempt to load more, in order to avoid displaying an empty screen for the next 2 minutes :-/ if (DEBUG) { console.log("LOADING NEXT PAGE !"); } if (options.mode == 'direct') { updateTweetsFromURL(options.URL_BASE_DIRECT + data.next_page+"&since_id="+lastRetrieved + "&callback=?"); } else { updateTweetsFromURL(options.URL_BASE_INDIRECT + data.next_page+"&since_id="+lastRetrieved); } } else { // we are not loading any other page... let's plan an update ? // plan next update ! planTweeterUpdate(options.delay); state.isInitialLoad = false; lastRetrieved = lastRetrievedNext; } } var err ; function updateTweetsFromURL (url) { if (DEBUG) { console.log("LOADING "+url); } $.ajax({ url: url, dataType: 'json', data: {}, success: processResults, timeout: options.timeoutGetTweets, error: function(jqXHR, status, errorThrown){ //the status returned will be "timeout" if (DEBUG) { console.log("error: "+errorThrown); } //$("#wait").hide(); //displayMessage('indirect'); planTweeterUpdate(options.delayRetryError); } }); } function updateTweets() { // no more pending updateHolder = undefined; var url2 = ""; if (options.mode == 'direct') { url2 = options.URL_BASE_DIRECT+'?callback=?&'; } else { url2 = options.URL_BASE_INDIRECT + '?'; } url2 = url2+'q='+searched+'&since_id='+lastRetrieved+"&rpp=100&result_type=mixed&include_entities=1"; // old &include_rts=1 url = url2; //displayMessage('loading'); $("#wait").show(); if (DEBUG) { console.log("refresh from url: "+url); } updateTweetsFromURL(url); } function initLoad() { if (urlParams.preset !== undefined) { var requiredIdx = parseInt(urlParams.preset); if (requiredIdx != NaN) { if (DEBUG) { console.log("loading preset with idx: "+requiredIdx); } // attempts to use this parameter to set the value guiElements.formparams.elements["preset"].options[urlParams.preset].selected = "1"; presedChoosed(); return; } } if (urlParams.query !== undefined) { if (DEBUG) { console.log("loading query : "+urlParams.query); } loadFromShort(decodeURI(urlParams.query)); return; } // default randompreset(); } function refresh() { changedParams(); } function initEverything() { $("#stop").click(function(){ stopLoadUpdate(); state.force.stop(); }); $("#refresh").click(function(){ refresh(); }); // don't hide the display when the user is willing to interact with it ! tweetdisplay.container.mouseover(function() { showTweetDisplay(); }); window.onload = initLoad(); } initEverything();