Thursday, November 12, 2009

Access Yahoo's Weather API via YQL and jQuery

Let me start off by saying that if you want a basic demo of YQL by grabbing an RSS feed check out my first blog post on YQL. In this post I am going to make a little weather widget that grabs the current temperature, weather condition, wind speed and direction, create a link to the full forecast and lastly drop a pretty weather condition graphic as the background of the widget. Then, once I have all that data I am going to display it via jQuery.

So let's get started! Pull up the YQL developer console: https://developer.yahoo.com/yql/console/ and type in:

select * from weather.forecast where location=29201

Select JSON and click test. This shows you the weather data for Columbia, SC in JSON format. The good stuff is located in the within data.query.results.channel. In there you have access to the current temperature, humidity, wind, wind direction and even sunrise and sunset times. So let's start off simple.

Notice the rest query url in YQL console? It reads:
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20location%3D29201&format=json&callback=cbfunc

That is a little tough to work with if you ask me so I like to bring in a little jquery to make this JSON url a little easier to work with and read. Here is a little piece of jquery that does just that for you:

$.YQL = function(query, callback) {
    var encodedQuery = encodeURIComponent(query.toLowerCase()),
        url = 'http://query.yahooapis.com/v1/public/yql?q='
            + encodedQuery + '&format=json&callback=?';
    $.getJSON(url, callback);
};


I generally include this little snippet in a file called jquery.yql.js. After that we can place our YQL query just like in the console. Here is our sample query:

$.YQL("select * from weather.forecast where location=29201",function(data){
            var w=data.query.results.channel;
            $('#weatherTemp').html(w.item.condition.temp+"°");
            $('#weatherText').html(w.item.condition.text);
       });  

This call grabs the weather information for Columbia, SC and injects the temperature and condition text to their corresponding divs. So data.query.results.channel.item.condition.temp = current temperature. and data.query.results.channel.item.condition.text = current condition.

So that was easy, let's grab all the information we want for this demo!

$.YQL("select * from weather.forecast where location=29406",function(data){
            var w=data.query.results.channel;
            var weatherImage="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.item.condition.code+"d.png)";
            var wd=w.wind.direction;
            if(wd>=348.75&&wd<=360){wd="N"};if(wd>=0&&wd<11.25){wd="N"};if(wd>=11.25&&wd<33.75){wd="NNE"};if(wd>=33.75&&wd<56.25){wd="NE"};if(wd>=56.25&&wd<78.75){wd="ENE"};if(wd>=78.75&&wd<101.25){wd="E"};if(wd>=101.25&&wd<123.75){wd="ESE"};if(wd>=123.75&&wd<146.25){wd="SE"};if(wd>=146.25&&wd<168.75){wd="SSE"};if(wd>=168.75&&wd<191.25){wd="S"};if(wd>=191.25 && wd<213.75){wd="SSW"};if(wd>=213.75&&wd<236.25){wd="SW"};if(wd>=236.25&&wd<258.75){wd="WSW"};if(wd>=258.75 && wd<281.25){wd="W"};if(wd>=281.25&&wd<303.75){wd="WNW"};if(wd>=303.75&&wd<326.25){wd="NW"};if(wd>=326.25&&wd<348.75){wd="NNW"};
            $('#weatherWidget').css("background-image",weatherImage);
            $('#weatherTemp').html(w.item.condition.temp+"&deg;");
            $('#weatherText').html(w.item.condition.text);
            $('#weatherWind').html(wd +" "+w.wind.speed+"mph");
            $('#weatherLink').html("<a href='"+w.item.link+"'>Full Forecast</a>");
        });

OK, let's go line by line. First off you wil notice that I created weatherImage variable. Yahoo does not give you the full url to the image. I have to build the url and insert the condition code to display the right image. So to make the weatherImage I take the string "http://l.yimg.com/a/i/us/nws/weather/gr/" and add the condition code "30" to it and append the string ".png" to that you get: http://l.yimg.com/a/i/us/nws/weather/gr/30d.png

Yahoo does not give you the text wind direction. It gives you the degree. So if w.wind.direction might equal "90" which equals East. But I actually want to display E or NE. etc... So I wrote a series of if statements to check the direction number and output a string. I know, I know. I could have written a regular expression, but hey, I am a designer. Cut me some slack!

The rest of it just injects all the data into the corresponding divs. So here is a working example:


Please note there is NO server side coding going on. This is just javascript, HTML, and a little css. Speaking of which, here is the html as well:

<div id="weatherWidget" style="background: rgb(51, 51, 51) none no-repeat scroll 0% 0%; border: 10px solid rgb(17, 17, 17); height: 150px; position: relative;">
<div id="weatherDescription" style="left: 200px; position: absolute; top: 40px;">
<div id="weatherTemp" style="font-size: 200%; font-weight: bold;"></div>
<div id="weatherText"></div>
<div id="weatherWind"></div>
<div id="weatherLink"></div>
</div>
</div>

Pretty simple stuff if you ask me. I am going to post some flickr, youTube, upcoming.org, and twitter YQL widgets in the near future. So stay tuned!