I truly enjoy the finer things in life. For example, if I’m going to eat a steak I don’t want some fatty low grade piece of meat. I would much rather (in this case, spend the additional money) to get an AAA grade of meat. The taste is worth it.
The same is true with development; the Twitter Timeline is “nice”, but I personally don’t want a linear, scrollable representation of my Tweets! I want the AAA grade where in this case it just takes a little bit more time instead of money… As you can see above, my Tweets are sliding in and out every 7.5 seconds. Once it cycles through my latest 10, it restarts again.
The first thing I need to do is parse this out. So my number 1 rule in coding, is don’t re-invent the wheel, someone has probably already done it. Quick research brought me to TwitStream. The goal of their code was more geared towards the Twitter Search API oppose to the user timeline, so I had to make a few alterations.
The fully updated twitStream.js is here:
[code]
/*
* TwitStream – A jQuery plugin for the Twitter Search API
* Version 1.2
* http://kjc-designs.com/TwitStream
* Copyright (c) 2009 Noah Cooper
* Licensed under the GNU General Public License http://www.gnu.org/licenses/
*/
String.prototype.linkify=function(){
return this.replace(/[A-Za-z]+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&;\?\/.=]+/g,function(m){
return m.link(m);
});
};
String.prototype.linkuser=function(){
return this.replace(/[@]+[A-Za-z0-9-_]+/g,function(u){
return u.link(“http://twitter.com/”+u.replace(“@”,””));
});
};
String.prototype.linktag=function(){
return this.replace(/[]+[A-Za-z0-9-_]+/,function(t){
return t;
});
};
var showTweetLinks=’none’;
var width = $(window).width();
function fetch_tweets(elem){
elem=$(elem);
keyword=escape(elem.attr(‘title’));
num=elem.attr(‘class’).split(‘ ‘).slice(-1);
var url=”https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=”+keyword+”&count=”+num+”&callback=?”;
$.getJSON(url,function(json){
$(json).each(function(count){
var tTime=new Date(Date.parse(this.created_at));
var cTime=new Date();
var sinceMin=Math.round((cTime-tTime)/60000);
if(sinceMin==0){
var sinceSec=Math.round((cTime-tTime)/1000);
if(sinceSec<10)
var since=’less than 10 seconds ago’;
else if(sinceSec<20)
var since=’less than 20 seconds ago’;
else
var since=’half a minute ago’;
}
else if(sinceMin==1){
var sinceSec=Math.round((cTime-tTime)/1000);
if(sinceSec==30)
var since=’half a minute ago’;
else if(sinceSec<60)
var since=’less than a minute ago’;
else
var since=’1 minute ago’;
}
else if(sinceMin<45)
var since=sinceMin+’ minutes ago’;
else if(sinceMin>44&&sinceMin<60)
var since=’about 1 hour ago’;
else if(sinceMin<1440){
var sinceHr=Math.round(sinceMin/60);
if(sinceHr==1)
var since=’about 1 hour ago’;
else
var since=’about ‘+sinceHr+’ hours ago’;
}
else if(sinceMin>1439&&sinceMin<2880)
var since=’1 day ago’;
else{
var sinceDay=Math.round(sinceMin/1440);
var since=sinceDay+’ days ago’;
}
var tweetBy='<a target=”_blank” href=”http://twitter.com/’+this.user.screen_name+'”>@’+this.user.screen_name+'</a> ‘+since;
if(showTweetLinks.indexOf(‘reply’)!=-1)
tweetBy=tweetBy+’ · <a target=”_blank” href=”http://twitter.com/?status=@’+this.user.screen_name+’ &in_reply_to_status_id=’+this.id+’&in_reply_to=’+this.user.screen_name+'”>Reply</a>’;
if(showTweetLinks.indexOf(‘view’)!=-1)
tweetBy=tweetBy+’ · <a target=”_blank” href=”http://twitter.com/’+this.user.screen_name+’/statuses/’+this.id+'”>View Tweet</a>’;
if(showTweetLinks.indexOf(‘rt’)!=-1)
tweetBy=tweetBy+’ · <a target=”_blank” href=”http://twitter.com/?status=RT @’+this.user.screen_name+’ ‘+escape(this.text.replace(/"/g,'”‘))+’&in_reply_to_status_id=’+this.id+’&in_reply_to=’+this.user.screen_name+'”>RT</a>’;
var tweet='<div’;
tweet+=’ style=”left:’+(count * width)+’px”‘;
tweet+=’>’+this.text.linkify().linkuser().linktag().replace(/<a/g,'<a target=”_blank”‘)+’ ‘+tweetBy+'</div>’;
elem.append(tweet);
});
});
return(false);
}
$(function(){
showTweetLinks=showTweetLinks.toLowerCase();
if(showTweetLinks.indexOf(‘all’)!=-1)
showTweetLinks=’reply,view,rt’;
$(‘.twitStream’).each(function(){
fetch_tweets(this);
});
});
[/code]
I only had to make a few subtle changes, firstly of course the URL, and secondly, the Tweeted by user required a slightly different JSON format.
I’ve also included code above that will get the current window width and offset the Tweets left position by the counter multiplied by the width. This is required when we start to slide the Tweets in and out.
The HTML required to embed this into my site is as follows:
[code]
<div id=”tweets” title=”endyourif”></div>
[/code]
The code supports multiple twitStream classes as well if you would like to embed multiple timelines. Updating the title and the count beside the twitStream class name is all you will need to do to further customize it.
Finally, for the good meat (pun intended). Below is a new function I created called cycle_tweets. It is called from a timer interval every XXXX milliseconds:
[code]
function cycle_tweets() {
var $children = $(“#tweets”).children();
var length = $children.length;
$children.each(function(count) {
var origLeft = parseInt($(this).css(‘left’));
var newLeft = origLeft – width;
$(this).animate({left: newLeft+’px’}, 1000);
// if we are the end and newLeft is 0, start again
if (count + 1 == length && newLeft == -width) {
$children.reverse().each(function(i) {
var theLeft = ((i-length+1)*-width);
$(this).animate({left: theLeft+’px’}, 500);
});
}
});
}
jQuery.fn.reverse = [].reverse;
[/code]
The above code loops through the children elements of the id tweets. It grabs the current left position and calculates a new left position. With this new left position, the element is then animated using Jquery Animate.
Once we’ve animated through all of the children, I am checking to see if all Tweets have been shown. If they have, the children are then reversed and animated back to their original starting position to begin the cycle anew.
One final change is required, the cycle_tweets function needs to be called when the Tweets are done being fetched.
[code]
$(‘.twitStream’).each(function(){
fetch_tweets(this);
// cycle through the tweets
setInterval(function() {cycle_tweets(this); }, 7500);
});
[/code]
This is a subset of the previous code, after the fetch_tweets function call; a new interval is created with setInterval that calls cycle_tweets every 7500 milliseconds or 7.5 seconds.
As I’ve stated before, I’m not a designer, so I’ll leave the styling up to you!