LottaTweets.com – web app for speed reading tweets

May 20, 2012 | By

As a developer evangelist for Adobe, I use Twitter often to keep up with the latest trends, announcements, and more.  I’ve often been frustrated that the Twitter website and twitter apps all use one column that takes advantage of only about 1/9th of my large monitor.  I’ve been looking for a good project to beef up my jQuery skills, and decided to see if I could build something to meet my own requirements for a tweet rapid-reader.

UPDATE April 5, 2013 — Twitter killed the Twitter Anywhere API so the app is broke.  I’ll try to refactor it soon to use the newer APIs.

What is it?

LottaTweets is a web-based tool that fills your screen with tweets in a multi-column, newspaper-style layout allowing super fast reading.  In addition to being able to quickly scan tweets, there are a few neat features:

  • Color coded retweet rate — Tweets are color-coded based on the number of re-tweets per minute.  It’s a quick way to visually identify tweets that others have found important enough to share.  There is also a button that will toggle filtering based on the retweet rate.  I originally was only using the re-tweet count, but I realized that it’s not a good measure since older tweets will always have more retweets than new tweets.  The re-tweet rate seems to work well.
  • Noise factor — Each tweet shows the noise factor of the tweeter.  The theory is that if you have tweeted 2000 times but only have 50 followers, you are “noisy”.  The noise factor is computed by number_of_tweets / number_of_followers.  There is also a button that will toggle filtering based on noise factor.
  • Infinite horizontal scrolling — you can keep scrolling right and it continues to load more tweets for you to read.
  • Auto-refresh — if you check the box for auto-refresh, it will prepend any new tweets every 60 seconds.
  • It’s read-only –  I configured my Twitter API endpoint to be read-only, so you don’t have to worry about the app tweeting anything on your behalf.  Each tweet has a link (timestamp) to the tweet on Twitter.com so you can reply, retweet, etc.  Each thumbnail image is a link to that user’s Twitter page.

Technical Details and the Development Experience:

  • Lotta tweets is a pure JavaScript app with no server infrastructure other than a web server and Twitter’s Anywhere APIs.
  • The layout is using CSS3 columns and works great with latest versions of Chrome, Firefox, and Safari.  It’s about 90% functional with Opera (there are some re-layout issues when filters are applied).  CSS3 columns are not supported by IE6/7/8/9, but should be available in IE10.  In order to support IE 6/7/8/9, I would need to use another means of multi-column formatting such as the jQuery columnizer plugin.  For now, I’m leaving it as-is.
  • I had a great head start on this project from Tom Germeau’s Fork-a-Twitter-Client (FATC) project.  This provided the basic Twitter API interactions and saved me some hours of hacking.  The project uses a StratifiedJS implementation called OniApollo.  This was the first time I’ve seen StratifiedJS.  It’s a clever way to simplify complicated asynchronous applications.
  • I found a few browser bugs (no web dev project would be complete without finding new browser bugs!):
    • Safari — I originally set each tweet div with overflow:hidden in case the tweet wrapped beyond the confines of the div.  This worked fine on Chrome, but on Safari, everything in columns two through n was hidden!  There were a lot of blank boxes with hidden text.  Only column one was correctly displayed.  I abandoned overflow:hidden for now since it’s very rarely needed.
    • Firefox — Firefox doesn’t use up all of the vertical space when laying out the divs.  I always had a blank space that was a few pixels taller than what is required to hold another row.  I believe that this is a layout issue because it only happens with Firefox.  As a workaround, if the user is using Firefox, I manually increase the height of the wrapper div to trick Firefox into thinking another row will fit.
    • Opera — when you resize the screen, or apply a filter, Opera doesn’t handle the re-layout correctly and things get a bit scrambled.
  • Mobile — The site runs great on desktop Chrome, Safari, Firefox and Opera.  It runs OK in Safari on iPad, but the scrolling is a bit un-refined and slow.  I’ll work on this soon.  I haven’t tested yet on an Android tablet.  iPhone and other mobile phones are really too small for this type of layout.
  • The font in the top bar is Felt Tip Roman, a font available on TypeKit.com, a fantastic service that I’ve only used once before on Phraffle.com.
  • I use Modernizr to check if the user’s browser supports CSS3 columns.  A simple alert() is displayed if not.
  • The Twitter Anywhere API uses OAuth to authenticate the user, but the cookie it drops is a session-only cookie, so you will have to re-connect each time you access the page after closing the browser.  The subsequent connects should only require a simple confirmation click and not your email/password.  If the site gets decent traction, I’ll look into using the “Sign into Twitter” APIs, which will give me more control over it.
  • Yes, I know, I need a designer! (don’t we all?!)
  • There is currently a bug – if you turn on a filter and it results in zero tweets, it will crash.  The workaround is to follow more people! ;-)
  • The code is a bit messy and still fairly hack-ish, but it’s fairly easy to understand.  View the source, and let me know if you have any suggestions.

Any suggestions on features?

Any suggestions on code/architecture?

Filed in: HTML5, JavaScript, JQuery, LottaTweets, Typekit | Tags: , , , , , , , , ,

About the Author (Author Profile)

Greg is a developer advocate for the Google Cloud Platform based in San Francisco, California
  • Trae Regan

    You, Sir, are on a roll — nice!

    • http://gregsramblings.com Greg Wilson

      Thanks! I just need more weekend coding time :)

  • Imrahil

    Is it possible to filter all RT and conversations? I need list only with statuses…

    • http://gregsramblings.com Greg Wilson

      The API tells me if the tweet is in reply to another tweet, so yes, I guess I could! Good idea – I’ll add.

      Greg

    • http://gregsramblings.com Greg Wilson

      I added this. Replies are green (until I get a better color scheme going). There is also a button to toggle them on/off.

      • Imrahil

        Awesome! Thanks! :)

  • http://twitter.com/webcuriousanima luntereiner

    Nice !
    There are good ideas in your application.
    The readability can be improved (font family, font-size, line-height…).

    I’ll try it for a couple of days!

    • http://gregsramblings.com Greg Wilson

      I’m open to any suggestions on fonts, etc. Finding fonts for really small text is a challenge!

  • Nene Odonkor

    There is one feature i want on twitter and that is TWEET organization. I will use facebook as an example. When someone posts an update there is a comment section where people can post comments relating to that post. I find it frustrating that I have scroll down to find out what was said. Recently, twitter introduced the button “view conversation” which is slightly helpful. Now i know twitter would no want to totally mimic facebook but there is way around it. For a every reply tweet, the main tweet is updated to indicate someone replied to that tweet and the number of tweets under it.. This will make it possible for people to be able to view all tweets under one conversation and the people involved.

  • http://slashdot.org/~tqft/journal tqft

    Anyway to get http://lottatweets.com/ show a list you may have?

  • http://www.darlingtons.com Darlingtons

    Just looking at the chart/infographic gave me a headache, seems complicated !

  • http://onilabs.com Alex Fritze

    Hi Greg,

    I’m one of the guys behind StratifiedJS and just stumbled across LottaTweets. It’s great stuff!

    I had a cursory look at the source and came across a couple of small things:

    You’re using a bunch of asynchronous event listeners (clicks on the refresh button, etc) in conjunction with blocking stratified logic (update_timeline_loop, etc). That’s perfectly fine, but with asynchronous logic there is always the danger of introducing race conditions and the like.

    In your case, you have the following race condition:
    Each time the user toggles ‘autoupdate’ to ‘true’, you spin up a new invocation of update_timeline_loop and update_mention_loop:

    $(“#autoupdate”).click(function() {
    if (document.getElementById(“autoupdate”).checked==true) {
    waitfor {
    update_timeline_loop();
    }
    and {
    update_mention_loop();
    }
    }
    });

    That’s ok if update_timeline_loop and update_mention_loop aren’t currently running, but consider what happens if they are. E.g. lets say they are waiting on data from twitter in ‘fetch_tweets’ and the user toggles the button to ‘on’. In this case you’ll end up with two concurrent invocations of these functions, and, as they are endless loops, and you only return from them if autoupdate is ‘false’, they will just all continue running alongside each other. Come the next timeout in 60s, all 4 of these concurrent invocations will hit the twitter API, and performing twice the number of requests that are actually necessary.

    The ‘traditional’ way of fixing this, would be to have some flag, e.g. update_timeline_loop_running, but in StratifiedJS this logic can be coded in a more direct and less disjointed way. Instead of $(“#autoupdate”).click(…), you can wait for a click directly in the endless loops. E.g. in update_timeline_loop, instead of

    waitfor {
    // Twitter is rate-limited to ~150calls/h. Wait for 60 seconds
    // until we fetch more tweets.
    hold(60 * 1000);
    }
    or {
    $(window).waitFor(“settingschanged”);
    $(“#mention”).empty();
    }
    if (document.getElementById(“autoupdate”).checked==false) break;

    You could do this:

    waitfor {
    // Twitter is rate-limited to ~150calls/h. Wait for 60 seconds
    // until we fetch more tweets.
    hold(60 * 1000);
    if (document.getElementById(“autoupdate”).checked==false)
    require(‘apollo:dom’).waitforEvent(‘autoupdate’, ‘click’);
    or {
    $(window).waitFor(“settingschanged”);
    $(“#timeline”).empty();
    }

    I.e. if the timeout has expired but ‘autoupdate’ is ‘false’, we wait indefinitely for the user to toggle the button before going round the loop again.

    Similarly, your handling of the refresh button is a bit problematic at the moment. Depending on when exactly it is clicked and whether ‘autoupdate’ is true, you end up with multiple redundant calls to update_timeline_loop and update_mention_loop. Again, the logic that you _really_ want can be coded directly into the loops, just by adding another clause to the waitfor/or:

    waitfor {
    // Twitter is rate-limited to ~150calls/h. Wait for 60 seconds
    // until we fetch more tweets.
    hold(60 * 1000);
    if (document.getElementById(“autoupdate”).checked==false)
    require(‘apollo:dom’).waitforEvent(‘autoupdate’, ‘click’);
    }
    or {
    $(window).waitFor(“settingschanged”);
    $(“#mention”).empty();
    }
    or {
    require(‘apollo:dom’).waitforEvent(‘refreshbutton’, ‘click’);
    }

    Finally, with both update_mention_loop & update_timeline_loop looking so similar, it might make sense to combine them into one function:

    function update_loop() {
    while (true) {
    // concurrently update mentions & timeline:
    waitfor {
    update_mentions();
    }
    and {
    update_timeline();
    }

    waitfor {
    hold(60*1000);
    if (document.getElementById(‘autoupdate’).checked == false)
    require(‘apollo:dom’).waitforEvent(‘autoupdate’, ‘click’);
    }
    or {
    $(window).waitFor(“settingschanged”);
    clear_timeline();
    clear_mentions();
    }
    or {
    require(‘apollo:dom’).waitforEvent(‘refreshbutton’, ‘click’);
    }
    }
    }

    Cheers,
    Alex

    • http://gregsramblings.com Greg Wilson

      Ah – thanks! I was definitely feeling like I was mixing methodologies a bit. I’ll make your suggested update.

      Greg

  • http://twitter.com/elfgoh Luther

    Would this happen to be an opensource project by any chance?

    • http://gregsramblings.com Greg Wilson

      Not yet – but I do plan to make my github repo public within the next 2 weeks – then you will have access. Stay tuned :)

      Greg

  • http://www.codex73.com francis suarez

    Hi Greg! I stumbled on this post after reading the other nice article about Twitter replies, very cool. I wrote some code to try to get my twitter feed uncluttered, which is something I don’t like (the noise level on the screen). I thought, I really will like to see 1-3 tweets at any given time, then move along to the next group. I will be super to get your input. http://outera.com/twitterfeed/

    • http://gregsramblings.com Greg Wilson

      Very cool!