Skip to content

Archive for October, 2011

Roll your own Tasteful Twitter Ticker

Twitter’s search widget is really nice. So nice that I use it unmodified on the right side of the front page of pr.ogra.ms. You’re supposed to put it on the sidebar of your blog and it will show a list of a specified number of past tweets vertically. You can have it display any user’s tweets or specify search terms. It has a limited number of other options which are enough for most applications. Sometimes you need something a little different though.

I’ve been working on a project for which a long list of past tweets might not be the best for visibility, layout or usability. The Photobot 3000 is a portable photo booth without the booth. It’s a small box that you set up facing a wall with chairs and a green screen. Party guests sit in the chairs and hit the big red button on the front of the box. A series of lights counts down and the box takes their picture. All of the pictures are then projected onto a screen for everyone to see.

The projected image is a browser running a web page in full screen mode. For certain events, we also want to show tweets adjacent to the photos using a custom hashtag. We’ve been using Twitter’s widget and it’s been working great, but there are a few things that could make it better.

First, the text is very small, making it hard to read from far away. If we’re at a venue that doesn’t have a proper screen and are instead projecting the images on a non-homogenous wall, the tweets are even harder to read. If people can’t read the tweets, they’ll be less likely to use the hashtag themselves and the Twitter widget will just become one big waste of space.

Second, having the list of tweets displayed vertically to the right of the photos limits how large we can display the photos. We need to make sure that the Twitter widget adds to the experience and doesn’t detract from the important portion of the display: the images.

Third, there are some filters that we’d like to put on the tweets to be displayed that the default Twitter widget doesn’t support. For example, we’d like to only show tweets from the same day as the event.

So I decided to start playing around with getting data from Twitter and try to see if I could create my own Twitter widget that only shows one tweet at a time and position it right below each photo.

Before we continue, let me just say that I’ve been skittish about using ticker-type displays ever since the introduction of the second most hated HTML tag: <marquee> (second to <blink>). But I think I’ve made a reasonable case for a Twitter ticker widget as long as I keep it tasteful.
I promise it’ll be better than this!

Twitter’s really easy

It turns out that Twitter is really easy to work with if you’re just reading public tweets. They expose an interface to get search results in JSON format without having to log-in. If you add in the ease of working with JSON data which jQuery provides (which you should because jQuery is awesome,) the code to get Twitter search results becomes pretty trivial:

function getTweets()
{
	var hashTag = "%23flyers";
	var maxTweets = 99;

	var JSONQuery = "http://search.twitter.com/search.json?q=" 
		+ hashTag + "&callback=?&rpp=" + maxTweets;

 	$.getJSON(JSONQuery, getTweetCallback);

}
function getTweetCallback(ob)
{
	tweets = ob;
}

This code’s pretty straightforward. I’m asynchronously calling the Twitter search with an arbitrary hashtag (%23 is the octothorpe character.) When the request is complete, the getTweetCallback method is invoked. The rpp option stands for Results Per Page. The maximum is 100 which is fine for my uses, but if you need more than that, you’ll have to call the JSON search multiple times with the paging query options and aggregate the results.

Ok, but what do we do with it?

So we’ve got all of the tweets, now what do we do? the variable ob now contains a member called results which is an array of tweets. Each element has a bunch of data about each tweet, but the members that we’re going to use are profile_image_url, from_user, and text. So for example, to access the text of the latest tweet, you would do:

ob.results[0].text

It’s not enough to just show the latest tweet though. We want to cycle through the list, showing each tweet for a few seconds. For this, we’re going to use the Javscript’s setTimeout function. setTimeout sets a one-time timer and after the prescribed duration invokes the specified callback method.

timer = setTimeout(showNext, interval);

The final piece of the puzzle is making it look pretty. Another reason that jQeury is a joy to use is jQuery UI. jQuery UI adds a method called .toggle that shows or hides an HTML element with a few different options for visual effects. The effects look great and are really easy to invoke.

var toggleType = "blind"
$( "#TwitterTicker" ).toggle(toggleType, options, "slow");

Pulling it all together, we have the following Javascript:

function getTweets()
{
	refreshNum = 0;

	if(timer)
		clearTimeout(timer);

	var JSONQuery = "http://search.twitter.com/search.json?q=" 
		+ hashTag + "&callback=?&rpp=" + maxTweets;

 	$.getJSON(JSONQuery, getTweetCallback);

}
function getTweetCallback(ob)
{
	tweets = ob;
	showNext();
}
function showNext()
{
	if(tweets.results.length > refreshNum+1)
 	{
 		var toggleType = "blind";
 		var options = {}

 		//Calling toggle from jQuery UI to 
 		//make the previous tweet invisible.
		$( "#TwitterTicker" ).toggle(toggleType, options, "slow", 
		function(){

 			//Using the tweet data
 			var text = 
			   "<img style='vertical-align:middle' src='"
			   + tweets.results[refreshNum].profile_image_url 
			   + "'/> <a href='twitter.com'>"
			   + tweets.results[refreshNum].from_user
			   + "</a> "
			   + tweets.results[refreshNum].text;
			
			$( "#TwitterTicker" ).html(text);

 			if(refreshNum >= maxTweets)
 				getTweets();
 			else	
 				refreshNum = refreshNum + 1;

 		});


		 //Calling toggle from jQuery UI to
 		 //make the new tweet visible
		 $( "#TwitterTicker" ).toggle(toggleType, options, "slow");


		 //Setting the timeout timer
		 timer = setTimeout(showNext, interval);
	 }
	 else
	 	getTweets();
}

The only slightly tricky part here is that I’m setting the text of the div element TwitterTicker in the callback for the toggle method that hides the div. This is so that the text of the tweet doesn’t change until the div is completely hidden. Here’s what it looks like:

One more thing

One more thing. setTimeout has this weird behavior on many browsers where if you switch tabs or the tab otherwise loses focus, when you return the browser tries to “catch up”. If you leave this code as-is, you may see a bunch of tweets flashing by quickly if you leave the tab and then come back. That’s pretty undesirable behavior here, so I added this code to the end of the Javascript file:

 $(document).blur(function(e) {
 	clearTimeout(timer);
 });
 $(document).focus(function(e) {
  	if(timer)
 	 	setTimeout(showNext, interval);
 }); 

This code disables the timer when the tab loses focus and restarts it when it gains focus again. The timer will start over at zero seconds when the focus comes back, but it’s better than playing catch up!

You can download the Javascript source here and an example html file here!