The Reactive Extensions for JavaScript Released
The long awaited day has come as the Reactive Extensions for JavaScript have been released on DevLabs in conjunction with the talk given by Erik Meijer at Mix 2010. Jeff Van Gogh, one of the principal developers on this project has more details and a detailed look at the sample application of “Time Flies Like an Arrow”. I’d like to also give a detailed explanation of another sample application, the Bing Maps and Twitter mashup.
Before we get started, let’s get caught up to where we are today:
- Introduction
- Creating Observables
- Creating Observers
- jQuery Integration
- Composing Callbacks
- From Blocking to Async
- Wikipedia Lookup
- Composing Deeper
Mashing Bing Maps and Twitter
One of the demos I’ve created is a mashup of Bing Maps and Twitter so that if the tweet has geolocation information attached that I’d display it on a map in near real time. What that means is that at a specified interval, we query the Twitter search API for something such as FourSquare, which has a higher probability of having some geolocation information attached and then display those results. So, how could we do this? Let’s walk through the example step by step.
First, we need to focus on the Bing Maps AJAX API which gives us the two main features we’re looking for, displaying a map and putting pushpins on it with some detailed information. In order to make use of it, we’ll need to link the Bing Maps AJAX library such as the following:
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"> </script>
Next, we’ll need a place to put our map, so, let’s create a simple <div> to host it.
<body> <div id="veMap" style="position:relative; width: 1000px; height: 600px;"></div> </body>
And then we’ll need our global map object that we can manipulate.
<script type="text/javascript"> var map = null; // More code goes here
Once we’ve defined that, we need a way to show the pushpin on the page. For this I’ll use the tweet ID for the overall pushpin ID, and I’ll take the date, latitude, longitude, their user icon URL, the user name and the text. From there, I’ll create a pushpin in that exact spot with the associated data. I have a try/catch block here where if I’ve seen that tweet before, the Bing Maps API doesn’t allow me to have multiple pushpins with the same ID, so I just ignore the failure.
function addPushPin( id, date, latitude, longitude, imageUrl, text, details) { try { var pinPoint = new VELatLong( latitude, longitude, 0, VEAltitudeMode.RelativeToGround); var detailText = date + "-" + details var pin = new VEPushpin(id, pinPoint, imageUrl, text, detailText); map.AddPushpin(pin); } catch(err) { // Seen it, don't worry } }
Moving onto the Twitter aspect of this, we’ll need a way to query Twitter using the Search API. In this case, we’ll once again use the XmlHttpRequest method with our URL which contains our text and a total request of 100 records per page.
function searchTwitter(text) { var url = "http://search.twitter.com/search.json?rpp=100&q=" + encodeURIComponent(text); return Rx.Observable.XmlHttpRequest(url); }
Once the page loads, we need to load the map, so in my document’s ready function, I initialize the VEMap with the ID of my <div>, load the map and set my zoom level to a nice globe shot.
$(document).ready(function() { map = new VEMap("veMap"); map.LoadMap(); map.SetZoomLevel(2);
Now we get to the interesting part. How do we reload the data every so often without running into the Twitter API limit? We can use the Interval method which we can set a due time before it invokes the action again. In this case, our action is going to be searching for FourSquare which returns an IObservable<IObservable<JSONData>> in C# parlance which we need to flatten and take the first one, so we’ll need the Switch method to do that.
Rx.Observable .Interval(10000) .Select(function() { return searchTwitter("foursquare"); }) .Switch()
Realizing that we’re dealing with JSON data, we need to safely parse it and in this case, I’m using the JSON2 library to do that. We’ll then take the JSON array and split it apart and turn each record into an observable with the SelectMany method. And since we’re only interested in those with geolocation, I check if they have any with my Where method.
.Select(function(result) { return JSON.parse(result.responseText); }) .SelectMany(function(data) { return data.results.toObservable(); }) .Where(function(data) { return data.geo != null; })
Finally, we can subscribe to the resulting observable. Our subscribing action is going to be adding a push pin with the JSON data as well as handle any potential errors.
.Subscribe( function(data) { var lat = data.geo.coordinates[0]; var lon = data.geo.coordinates[1]; addPushPin( data.id, data.created_at, lat, lon, data.profile_image_url, data.from_user, data.text); }, function(error) { alert(error); });
The code in its entirety can be found here. And below is the result of our code where we see the icons of the Twitter users who mention FourSquare after we leave it running for just a few short minutes…
We could take this example further to expire the pushpins over time, but I think overall, it’s a great example of asynchronous programming in JavaScript and how you can integrate it into your APIs.
Conclusion
Through the use of the Reactive Extensions for JavaScript, we’re able to mash two APIs together through AJAX and refresh them at a certain interval, keeping a near real-time feel to it. That’s just one of the many things we can do with it that I’ll hopefully cover more in the near future. So, download it, and give the team feedback!
What can I say? I love JavaScript and very much looking forward to the upcoming JSConf 2010 here in Washington, DC where the Reactive Extensions for JavaScript will be shown in its full glory with Jeffrey Van Gogh (who you can now follow on Twitter). For too many times, we’ve looked for the abstractions over the natural language of the web (HTML, CSS and JavaScript) and created monstrosities instead of embracing the web for what it is. With libraries such as jQuery and indeed the Reactive Extensions for JavaScript gives us better tools for dealing with the troubled child that is DOM manipulation and especially events.