Ryan Creighton’s Flash development site Untold Entertainment has a quirky home page with plenty of animation and things to click on (complete with roll-out tongue) and of course is built in Flash. Thing is, I’m against any kind of Flash interface. It’s great for games, but otherwise it’s unnecessary (which includes videos).
With the whole Adobe v Apple debate that’s going on right now (yes, I said I wouldn’t mention it but it applies here ‘kay), it’s safe to say you’d be better placing your chips on the JavaScript and HTML5 end of the table.
The discouraging part is that his website could be done without Flash as most of the scrolling and animating could be done with straight JavaScript, and jQuery will help see things along smoothly.
Today I’ll show you how to animate the text at the top, feeding in from his Twitter feed, complete with jerky timings, slanted text and collecting feed data.
Check out the Untold Twitter bar demo.
Including jQuery, Timer plugin, and Google AJAX Feed API
We’ll start off by including our libraries and plugins. Here I use jQuery, the jQuery Timers plugin, and the Google AJAX Feed API – all sourced from their Google Code hosts.
Admittedly we won’t be using much jQuery here as the code changed quite a bit as it got added to, but it might come in handy in later tutorials. If you know how to change the scripts into plain JavaScript, by all means change those parts over.
1 2 3 4 5 6 | <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript" src="http://stikked.googlecode.com/svn/trunk/static/js/jquery.timers.js"></script> <script type="text/javascript" src="http://www.google.com/jsapi?key=YOURAPIKEY"></script> <script type="text/javascript"> </script> |
More information on the API key can be found in my earlier post on Google AJAX Feeds.
This code goes inside the <body>
element, right at the top so it loads first. There’s an extra element in there – this is where we’ll add our own JavaScript.
Settings and Variables
To allow us to fine tune the feel of the page later, we’ll set up a list of variables. This bit of code is the first to go inside the empty <script>
tag above.
1 2 3 4 5 6 7 8 9 | /* Variables - tweak as you like */ var username = 'UntoldEnt'; var feed_url = 'http://twitter.com/statuses/user_timeline/21834006.rss'; var entry_fetches = 10; var interval = 50; var wait = 6000; var length_min = 4; var length_max = 6; |
These should be reasonable to understand, and what isn’t obvious will be covered later as the script develops.
Collecting Feed Data
In this example we want to collect the data from Twitter, or more specifically @untoldent‘s account. More information on the use of the google
object can be found on the same link as above (the Google Feed one).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /* Google Feed API stuff */ var updates = []; function Initialize() { var feed = new google.feeds.Feed(feed_url); feed.setNumEntries(entry_fetches); feed.load(function(result) { if(!result.error) { for(var i in result.feed.entries) { var entry = result.feed.entries[i].title.substr(username.length + 2); if(entry.substr(0, 1) != '@' && entry.substr(0, 2) != 'RT') { updates.push(entry.split(' ')); } } } set_timer(); }); } google.load("feeds", "1"); google.setOnLoadCallback(Initialize); |
We start off by collecting the RSS feed from the feed_url
and check there are no errors like I did before.
The script then loops through each feed element once it has been loaded in and removes replies and retweets. What’s left is added to our array of updates
, split word by word into another array inside of it.
When this is done, set_timer()
is called to start the actual stuff that makes it look like Untold’s Twitter bar.
Creating Animated Text
Last bit of JavaScript – the fancy part.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /* Animated Tweet stuff */ function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); } var word_key = 0; var update_key = 0; function set_timer() { var length = clamp(updates[update_key][word_key].length, length_min, length_max); var timing = length * interval; $('#container').oneTime(timing, 'label_' + word_key, add_text); } function add_text() { var rand = Math.ceil(Math.random() * 4); var new_text = $('#container').html() + ' <span class="rot' + rand + '">' + updates[update_key][word_key] + '</span>'; $('#container').html(new_text); word_key++; if (word_key < updates[update_key].length) { set_timer(); } else { $('#container').oneTime(wait, 'reset', function() { $('#container').html(''); word_key = 0; update_key++; if (update_key > updates.length - 1) { update_key = 0; } set_timer(); }); } } |
clamp: In other languages, clamp
is usually available inside a Math
library, but not this one. So I’ve added this to make the code cleaner later.
word_key and update_key: These are indexes for the updates
array and the words inside each element. These increment by one as they are used, and then reset to zero when moving to a new element. They’re kept outside the functions so that they can be called from wherever.
set_timer: First calculates a timing based on the length of the word. To avoid certain words appearing too quickly or slowly, the length_min
and length_max
are used from earlier to add a constrained limit on either side. It is then multiplied by interval
– also set earlier – to work out our timer.
The Timers plugin is then used to add a timer to the container element. This will call add_text()
after the set time from our previous word length is up.
add_text: Starts by setting a random number. This sets our rotation later, based on four classes in a stylesheet. Each word is contained within a <span>
element to treat each rotation separately.
The .html()
method inside jQuery allows us to add HTML markup inside of our container. Here we add our new element (the <span>
with a new word) onto the existing DOM.
When the word has been added, the index increases by one to access the next word. A timer is then set to add this word to the queue, which then adds it on the same way as before.
If there are no words left (i.e., the tweet has ended), the script stops for a period defined by wait
and some variables are reset to prepare for a new word. This includes word_key
, update_key
(if needed), and resets the HTML inside the container back to being empty.
Again, the timer is reset to prepare for new words to be added in, once the script has come out of its pause.
Rotation Styles
To keep with the quirky feel of Untold’s header, the text in the tweet bar also tilts word-by-word. As we have already set up our span elements with rotation classes, all that’s left is to style them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <style type="text/css"> #container { font-size:1.4em; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; } .rot1 { -webkit-transform: rotate(1deg); -moz-transform: rotate(1deg); rotation: 1deg; } .rot2 { -webkit-transform: rotate(2deg); -moz-transform: rotate(2deg); rotation: 2deg; } .rot3 { -webkit-transform: rotate(-1deg); -moz-transform: rotate(-1deg); rotation: -1deg; } .rot4 { -webkit-transform: rotate(-2deg); -moz-transform: rotate(-2deg); rotation: -2deg; } </style> |
As you can see, these styles use WebKit and Mozilla transforms so they’re not native to all browsers. The rotation
attribute is also only available as part of CSS3, so again not all browsers will be using this.
The latest version of Firefox runs it fine, although I found problems with the latest Chrome and Safari strangley, even though they use WebKit. Basically, if the text doesn’t look slanted your browser doesn’t support rotation
And that’s it. I’ll be seeing how far I can go with these scripts into a pure Flash-less home page.
Next I’ll be adding to this Twitter bar a bit more and taking it from there.
I’d like to know what you think of this project. Should JavaScript be used as a preference over Flash for interface design? Are there parts of Ryan’s home page that can’t possibly be made in this way?
Let me know in the comments, or rant at me on Twitter.